Sales Forecasting
The first problem deals with generating the forecasts of 75 time series. Each time series corresponds to the demand for a specific product (brand) in a geographic area (cluster). The time series are in monthly granularity.
We have been provided with the demand history for each of the series, so that by training statistical models in the past, we should be able to model behaviors that are likely to be repeated in the future. Therefore, with time series models we should be able to tackle the problem.
There are different techniques to tackle this problem, the “bottom-up” and the “top-down” approach.
A simple method for generating coherent forecasts is the “bottom-up” approach. This approach involves first generating forecasts for each series at the bottom level, and then summing these to produce forecasts for all the higher level series. Other approaches are the “top-down” whose involve first generating forecasts for the total series, and then disaggregating these down to all the levels.
The method chosen for this problem is the “bottom-up” approach because with this method we do not loss any information due to aggregations and because with only 75 series is a feasible approach.
Recall how the data looks like
| id |
cluster |
brand |
date |
sales_1 |
sales_2 |
investment_1 |
investment_2 |
investment_3 |
investment_4 |
investment_5 |
investment_6 |
| Cluster 9__Others |
Cluster 9 |
Others |
2018 Oct |
0 |
0 |
22.2 |
0.0 |
0.0 |
-1.8 |
0 |
0.0 |
| Cluster 9__Others |
Cluster 9 |
Others |
2018 Nov |
0 |
0 |
-5.5 |
-7.0 |
-1.6 |
-0.6 |
0 |
-2.4 |
| Cluster 9__Others |
Cluster 9 |
Others |
2018 Dec |
0 |
0 |
-7.2 |
-3.1 |
-1.6 |
-0.6 |
0 |
-2.4 |
The training process will be divided into the following steps:
- Define a list of models to use.
- Train the models using the training data
- Create the forecasts for the validation data
- Evaluate the performance of the models
Evaluation metric
The competition metric is the Mean Absolute Percentage Error (MAPE).
\[
MAPE = \frac{100}{h} \sum^{h}_{t=1}\frac{y_{t} - \hat{y}_{t} }{y_{t}}
\]
where \(y_t\) is the actual value and \(\hat{y}_t\) is the predicted value.
Percentage errors have the advantage of being unit-free, and so are frequently used to compare forecast performances between data sets.
Measures based on percentage errors have the disadvantage of being infinite or undefined if \(y_t=0\) for any \(t\) in the period of interest, and having extreme values if any \(y_t\) is close to zero. Makridakis (1993) said that “equal errors above the actual value result in a greater APE than those below the actual value”. He provided an example where \(y_t = 150\) and \(\hat{y}_t = 100\), so that the relative error is \(\frac{50}{150} = 0.33\), in contrast to the situation where \(y_t = 100\) and \(\hat{y}_t = 150\), when relative error would be \(\frac{50}{100} = 0.5\). Thus, MAPE puts a heavier penalty on negative errors (when \(y_t\) < \(\hat{y}_t\)) than on positive errors.

In the x-axis we have the absolute error and in the y-axis de MAPE. Absolute error are the number of units above or below the real value, i.e if the real value is 100 and the error is 50 then the predicted value has been 150. For the same error, as lower the true vale it is, the bigger the error we have.
Split data
As we are dealing with monthly time series data we will split the series using time rather than randomly as we usually do when training machine learning models. We will keep apart the last year of the data.
The datasets will be as follows:
[1] "Train data period: 2012 Jan - 2016 Dec"
[1] "Valid data period: 2017 Jan - 2017 Dec"
[1] "Test data period: 2018 Jan - 2018 Dec"
Baseline models
Before doing nothing, let’s compute some statistical baselines for all the series, that is, statistical models that just repeat the last value (NAIVE) or the last period of samples (SNAIVE).
The models that we are going to use as a benchmarks are:
NAIVE: this model replicate the last value of the sales data. This model is equivalent to an \(ARIMA(0,1,0)\) model.
SNAIVE: this model replicates the last period of samples from train data. This model is equivalent to an \(ARIMA(0,0,0)(0,1,0)_m\) model, where m is the seasonal period (m = 12 in monthly data.)
# Baseline models
models <- list(
naive = NAIVE(sales_2),
snaive_1 = SNAIVE(sales_2 ~ lag("year") ),
snaive_2 = SNAIVE(sales_2 ~ lag("year") + drift() )
)
Fit baseline models
fit_baselines <- train_data %>%
model(!!!models)
Generate forecast for all the models. Three different forecast will be generated for each serie.
fc_baselines <- fit_baselines %>%
forecast(new_data = valid_data)
The metric that we will use to evaluate the performance of each model is the MAPE but I will also include the RMSSE and CRPS for completeness. For both, the RMSE and the MAPE, the smaller the better.
The best model has been the naive with a MAPE of 26.9, followed by the two variants of the snaive. An error of a MAPE of 26.9 means that the model has an error of 26.9%.
| .model |
RMSSE |
MAPE |
CRPS |
| naive |
17.1 |
26.9 |
1224.8 |
| snaive_1 |
17.3 |
29.9 |
1174.4 |
| snaive_2 |
17.3 |
30.1 |
1197.3 |
Now that we have the forecast and we know what has been the best model, let’s visualize the forecast to get insight into the data.
Although the snaive model has performed better overall, in some series it performs worse than the snaive.

We also find differences between the snaive models. In the following plot we can see how the snaive with drift is under-forecasting while the other, without drift, is providing an acceptable forecast.

Sometimes no model is good.

Statistical Benchmarks
Exponential smoothing and ARIMA models are the two most widely used approaches to time series forecasting, and provide complementary approaches to the problem. While exponential smoothing models are based on a description of the trend and seasonality in the data, ARIMA models aim to describe the autocorrelations in the data.
ARIMA: autoregressive integrated moving average model
ETS: exponential smoothing models are based on a description of the trend and seasonality in the data
When there are long seasonal periods, a dynamic regression with fourier terms is often better than ARIMA and ETS models.
For example, daily data can have annual seasonality of length 365, weekly data has seasonal period of approximately 52, while half-hourly data can have several seasonal periods, the shortest of which is the daily pattern of period 48.
Despite we do not have long seasonal periods here, this models will be included in our list of models.
FOURIER: Linear regression model with errors modeled with an arima model to remove the autocorrelation.
Additionally to this models, it has also been included a combination forecast of ARIMA and ETS models which has been called combn.
models_stat <- list(
# Statistical benchmarks
arima = ARIMA(sales_2),
ets = ETS(sales_2),
# Using Fourier terms and ARIMA errors for forecasting
`K = 1` = ARIMA(sales_2 ~ fourier(K = 1) + PDQ(0, 0, 0)),
`K = 2` = ARIMA(sales_2 ~ fourier(K = 2) + PDQ(0, 0, 0)),
`K = 3` = ARIMA(sales_2 ~ fourier(K = 3) + PDQ(0, 0, 0)),
`K = 4` = ARIMA(sales_2 ~ fourier(K = 4) + PDQ(0, 0, 0)),
`K = 5` = ARIMA(sales_2 ~ fourier(K = 5) + PDQ(0, 0, 0)),
`K = 6` = ARIMA(sales_2 ~ fourier(K = 6) + PDQ(0, 0, 0))
)
The best model is the combn, followed by the ARIMA and the K = 2 models. The error has been reduced by 26.4% with respect to the naive model.
| .model |
RMSSE |
MAPE |
CRPS |
| combn |
16.7 |
19.8 |
797.7 |
| arima |
16.9 |
20.4 |
827.0 |
| K = 2 |
16.8 |
21.6 |
875.1 |
| ets |
16.8 |
21.8 |
841.9 |
| K = 5 |
16.9 |
21.8 |
926.6 |
| K = 4 |
17.0 |
21.8 |
935.6 |
In the example below, neither model has generated a good forecast, in fact, it seems that the ets model only has captured the trend.

In this other case, both forecasts are similar to each other and the snaive_1

Again, none of the models has been able to capture the big drop off of 2017.

Piecewise regression
We have seen that, in some cases, the trend is not linear and the models are not able to model the series correctly. Piece-wise models divide the series into several segments in such a way that they are able to detect the trend correctly.
Brand analysis
Performing the analysis for each series is a complicated and time-consuming task. For this reason, many times higher levels of aggregation are analyzed and then these conditions or parameters are applied to lower levels series.
The plot of the Brand Group 31 reveals two different periods. There is a clear uptrend up to the end of 2015. After 2015 there is a decrease in the growing speed and the trend slow down a bit. To account for these changes, we specify the date 2015-01 as knots.
# Select a brand a fit a model
current_brand <- "Brand Group 31"
# Fit simple `lm` and `piecewise` model
fit_trends <- by_brand_tsibble %>%
filter(brand == current_brand) %>%
model(
lm = TSLM(sales_2 ~ trend()),
piecewise = TSLM(sales_2 ~ trend(
knots = tsibble::yearmonth("2015-01")))
)

In the plot below the relationship between the real and adjusted values by the model is shown. The slashed line represents the perfection, in such a way that the further the points are from the line, the worse the model is. In the lower left corner, the values of the piecewise model are much better adjusted to the reality while those of the lm are farther away. In general, there is a bigger dispersion in the lm model than in the piecewise.

The models are defined manually for each brand.
get_models_ <- function(brand) {
# Define step-wise models
mdl <- null_model()
if (brand == "Brand Group 17") {
mdl <- TSLM(sales_2 ~ trend(knots = tsibble::yearmonth("2015-03")) + season())
} else if (brand == "Brand Group 24") {
...
}
}
In brands such as Brand Group 17 or Brand Group 24 the effect is remarkable. It is also in others, such as the Brand Group 31 as we have just seen in the previous plots.

All series analysis
Now that we have identified the knots of each brand is time to apply this models into the product level series.
fit_stepwise <- map_dfr(
.x = setNames(brands, brands),
.f = ~ train_data %>%
filter(brand == .x) %>%
model(!!!get_models(.x)["stepwise"]),
.id = "brand"
)
Overall accuracy is not as good as combn, arima orets models trained on statistical benchmarks section
| .model |
RMSSE |
MAPE |
CRPS |
| stepwise |
16.9 |
24 |
1077.7 |
Let’s look at some of the worst forecast. The arima and ets models will be included as a reference. In that way, we can understand how the piecewise model is modeling the data. In the following case, it seems that the model has failed to capture the trend correctly and is under-forecasting much more than the other two models.

What we can do now? Let’s plot the trend to understand why this is happening. The model fits very well the trend up to 2016 but, after that period, the trend is still in a downtrend and it should remain almost flat. The vertical dashed lines indicate the knots defined within the model.

Finally, we show the forecast for the series that we have been looking in the previous sections.

fit_stepwise %>%
filter(id == "Cluster 2__Others") %>%
left_join(select(fit_statistical, id, ets, arima), by = "id") %>%
forecast(new_data = valid_data) %>%
plot_forecast(facets = ".model", ncol = NULL, level = NULL, title = "") +
facet_wrap(~ id)

Selecting best model
Throughout the notebook we have seen how each model is better suited to one specific case, in some cases a model as simple as the naive give us the best results, however, in other cases we need more complex models to capture the signal of the series. So, why not select the best model for each series instead of always using the same model for everything?
# Combine all accuracies together
acc_all <-
bind_rows(acc_baselines, acc_statistical, acc_xreg, acc_stepwise) %>%
add_rank(var = "MAPE")
# Select best model for each serie
acc_best_models <- acc_all %>%
arrange(id, rank) %>%
top_n(-rank, n = 1) %>%
dplyr::group_by(id) %>%
dplyr::slice(1) %>%
ungroup()
The error has been reduced by an 47% with respect to the naive and 28% with respect to the combn model.
acc_best_models %>%
summarise_at(vars(RMSSE:CRPS), mean) %>%
add_column(.model = "Best model", .before = 1) %>%
arrange(MAPE) %>%
to_html(digits = 1)
| .model |
RMSSE |
MAPE |
CRPS |
| Best model |
16.5 |
14.1 |
602.1 |
How many times each model has been selected? stepwise and arima are the two best models followed by xreg_4. Recall that this model uses all the investments provided.

In the same way that we have been doing, we are going to show the best and worst predictions to get an idea of what the predictions are like.
# Combine all forecasts
fc_all_models <- bind_rows(fc_baselines, fc_statistical, fc_xreg, fc_stepwise)
fc_best_models <- fc_all_models %>%
semi_join(acc_best_models, by = c(".model", "id"))

Sometimes, any model is able to predict the data accurately. Might be, because the series are white noise or the signal-to-noise ratio is very low. Other times, there are very abrupt changes that cannot be explained by any predictor (past sales, investments, etc.)

Drill down accuracy
Forecasts are often required for all levels of the series, and it is natural that the forecasts to add up in the same way as the data. This is important because the forecast will be analyzed from different points of view and all of them must be aligned. For example, a brand manager might be interested in the forecast of all of their products but it also would might get a view at country level of their brand. At the same time, the CEO of the company, might be interested in higher levels of aggregation.
The easiest brand to forecast is Brand Group 96, 97 and the hardest is Brand Group 24 which is not a surprise given it’s highest growth.
| .model |
brand |
RMSSE |
MAPE |
CRPS |
| Best model |
Brand Group 96, 97 |
0.5 |
6.6 |
208.9 |
| Best model |
Others |
0.4 |
6.8 |
1315.0 |
| Best model |
Brand Group 31 |
0.3 |
6.9 |
765.8 |
| Best model |
Brand Group 41 |
0.5 |
7.7 |
470.8 |
| Best model |
Brand Group 51, 73, 90 |
0.4 |
8.2 |
281.9 |
| Best model |
Brand Group 17 |
0.5 |
9.0 |
362.4 |
| Best model |
Brand Group 30 |
0.5 |
9.1 |
444.1 |
| Best model |
Brand Group 36 |
1.2 |
19.2 |
178.2 |
| Best model |
Brand Group 24 |
1.4 |
20.1 |
227.3 |
In the same way, the easiest cluster is Cluster 8 and the hardest is Cluster 7
| .model |
cluster |
RMSSE |
MAPE |
CRPS |
| Best model |
Cluster 8 |
0.6 |
6.2 |
270.8 |
| Best model |
Cluster 2 |
0.5 |
6.3 |
512.4 |
| Best model |
Cluster 10 |
0.5 |
6.6 |
479.5 |
| Best model |
Cluster 9 |
0.5 |
8.1 |
168.1 |
| Best model |
Cluster 1 |
0.3 |
8.9 |
386.3 |
| Best model |
Cluster 3 |
0.5 |
9.7 |
1018.2 |
| Best model |
Cluster 4 |
0.6 |
16.0 |
644.1 |
| Best model |
Cluster 5 |
0.9 |
16.4 |
208.9 |
| Best model |
Cluster 7 |
0.9 |
27.4 |
275.4 |
Make forecasts
The last step is generate the forecast for all the 75 series. Now, we must estimate the models again but using all the data available.
# Combine all three list of models
models_list <- c(models, models_stat, models_xreg)
# Fit models using all train data
fit_all_models_1 <- train_data %>%
bind_rows(valid_data) %>%
model(!!!models_list) %>%
mutate(combn = (arima + ets) / 2)
# Train piece-wise models
fit_all_models_2 <- map_dfr(
.x = setNames(brands, brands),
.f = ~ train_data %>%
bind_rows(valid_data) %>%
filter(brand == .x) %>%
model(!!!get_models(.x)["stepwise"]),
.id = "brand"
)
# Combine all models together
fit_all_models <- fit_all_models_1 %>%
left_join(fit_all_models_2, by = "id")
# Save models
write_rds(fit_all_models,
file.path(path_models, "fit_all_models.rds"),
compress = "gz")

Resource Allocation
Resource allocation methods can be used in almost every aspect of supply chain management. The common goal is allocate the resources effectively (i.e., maximizing the revenue, minimizing the cost, or optimizing the utilization sequence) while satisfying certain constraints (e.g., resource availability, customer service level, back order level, delivery window). In this case, resources refers to investments.
In this second part of the challenge, Novartis ask to the participants to provide the optimal allocation of their resources for the year 2018, as well as, showing differences of allocations by cluster/brand/investment type and impact on sales. Investments are now compressed into Investment 1, Investment 2 and Others.
The template file provided by the organization looks as follow:
| cluster |
brand |
function |
OptimiseInvestment |
ForecastedSales |
OptimiseSales |
| Cluster 1 |
Brand Group 17 |
Investment 1 |
NA |
NA |
NA |
| Cluster 1 |
Brand Group 17 |
Investment 2 |
NA |
NA |
NA |
| Cluster 1 |
Brand Group 17 |
others |
NA |
NA |
NA |
Create the new variable investment_others, and remove unnecessary columns.
alloc_df <- all_levels_tbl %>%
mutate(
investment_others = investment_3 + investment_4 +
investment_5 + investment_6
) %>%
select(-c(investment_3, investment_4, investment_5, investment_6))
| id |
cluster |
brand |
date |
sales_1 |
sales_2 |
investment_1 |
investment_2 |
investment_others |
| Cluster 1__Brand Group 17 |
Cluster 1 |
Brand Group 17 |
2012 Jan |
0 |
0 |
0 |
0 |
0 |
| Cluster 1__Brand Group 17 |
Cluster 1 |
Brand Group 17 |
2012 Feb |
0 |
0 |
0 |
0 |
0 |
| Cluster 1__Brand Group 17 |
Cluster 1 |
Brand Group 17 |
2012 Mar |
0 |
0 |
0 |
0 |
0 |
Forecasting model
We need a forecasting model with investments as predictors. Ideally, the model obtained in the first challenge is the one that we should use to perform the optimization. However, some of the models are univariate and in any case the variable investment_others has been used. Therefore, a linear regression model will be used, which will use the trend, the seasonality and the investments as predictors.
Note: we should look for the best model possible that contains investments as predictors.
models_alloc <- list(
lm = TSLM(sales_2 ~ trend() + season() + investment_1 + investment_2 +
investment_others)
)
Then, train the models and generate the forecasts for the next 12 months
# Train models
fit_alloc <- train_data_alloc %>%
model(!!!models_alloc)
# Generate forecasts for the test period
fc_alloc <- fit_alloc %>%
forecast(new_data = test_data_alloc)
Simulations
When a closed form is not available to estimate the value of a parameter, either because it does not have a closed form formula or because there are too many factor that influence in the final result, the use of simulation techniques are commonly used to observe the behavior of the variable to be analyzed.
The model will be fed with variations of the investments to obtain different forecasts. Sometimes reducing the amount invested on one side to place it in another can lead to better results, and vice versa.
The steps to follow are:
- Create a matrix with the weights combinations
- Calculate the new simulated investments
- Generate the forecast with the new simulated values
Simulation weights
We create a mesh of values that allow us to evaluate different scenarios. The following restrictions have been applied:
The weights must add up to 1
In order to diversify, the maximum allocation will be 80% of the capital.
| comb_id |
comb_desc |
investment_1 |
investment_2 |
investment_others |
| 1 |
[0.00, 0.20, 0.80] |
0 |
0.20 |
0.80 |
| 2 |
[0.00, 0.25, 0.75] |
0 |
0.25 |
0.75 |
| 3 |
[0.00, 0.30, 0.70] |
0 |
0.30 |
0.70 |
| 4 |
[0.00, 0.35, 0.65] |
0 |
0.35 |
0.65 |
| 5 |
[0.00, 0.40, 0.60] |
0 |
0.40 |
0.60 |
| 6 |
[0.00, 0.45, 0.55] |
0 |
0.45 |
0.55 |
A total of 189 combinations per series will be evaluated.
Create scenarios
To generate the multiple scenarios we must multiply the weights generated in the previous section with the values of the investments. To do this, we will help ourselves with the following function:
get_future_scenerarios <- function(future_data, weights_df) {
# Store id data
id_df <- future_data %>%
select(id, date)
# Calculate total invested in each product-month
total_invested <- future_data %>%
transmute(total = rowSums(across(contains("investment"))))
# Repeat `total_invested` column 3 times (one for each investment)
inv <- replicate(n = 3, total_invested$total)
# Loop through weights
inv_cols <- str_subset(names(weights_df), "investment")
scenarios_list <- vector("list", length = nrow(weights_df))
for (i in seq(1, nrow(weights_df))) {
# Weights for this iteration
w <- weights_df[i, inv_cols]
w <- as.numeric(w)
# New investments
new_investments <- t(w * t(inv))
colnames(new_investments) <- inv_cols
future_scenario <- id_df %>%
bind_cols(weights_df[i, "comb_id"]) %>%
bind_cols(as_tibble(new_investments))
scenarios_list[[i]] <- future_scenario
}
# Return a list with all the simulations
scenarios_list
}
In gray-blue color we see the possible scenarios of the forecast. Each scenario corresponds to a different weight combination. In orange we have the median and in another shade of blue the 80th quantile.

Find optimal values
We will use the 80th quantile as the best combination. We could use the combination of parameters that has generated the greatest benefits, but it would be select the best optimistic scenario and we prefer to be more conservative.
First, we calculate the total amount of each simulation
simulations_agg <- fc %>%
as_tibble() %>%
group_by(id, comb_id) %>%
summarise(across(contains(".mean") | contains("investment"), sum)) %>%
ungroup() %>%
rename(OptimalSales = .mean) %>%
arrange(desc(OptimalSales)) %>%
left_join(select(weights_df, comb_id, comb_desc), by = "comb_id")
Then, select the combination that meets our requirements: pct_rank <= 0.8
# Find best combination of weights for each `id`
optimal_simulation_id <- simulations_agg %>%
group_by(id) %>%
summarise(
comb_id = comb_id,
OptimalSales = OptimalSales,
pct_rank = percent_rank(OptimalSales)
) %>%
# Select 80 percentile
filter(pct_rank <= 0.8) %>%
slice_max(pct_rank) %>%
# In case of tie, choose the first one. This happens
# in `Cluster 5__Brand Group 30`
slice_head(n = 1) %>%
ungroup()
Finally, prepare the output data
| id |
function |
OptimiseInvestment |
ForecastedSales |
OptimalSales |
| Cluster 3__Brand Group 31 |
investment_1 |
-5851 |
427441 |
442260 |
| Cluster 3__Brand Group 31 |
investment_2 |
-4388 |
427441 |
442260 |
| Cluster 3__Brand Group 31 |
investment_others |
-19016 |
427441 |
442260 |
| Cluster 2__Brand Group 41 |
investment_1 |
-1311 |
354095 |
412700 |
| Cluster 2__Brand Group 41 |
investment_2 |
-13107 |
354095 |
412700 |
| Cluster 2__Brand Group 41 |
investment_others |
-11796 |
354095 |
412700 |
According to the simulation results, we could have had a profit of ~ 500k in 2018.
| Year |
OptimiseInvestment |
ForecastedSales |
OptimalSales |
Profit |
| 2018 |
-457078 |
7366401 |
7885967 |
519566 |
Evolution of investments
The evolution of the investments over the years is shown below.It can be seen how, in general terms, the investments for 2018 are aligned with the historical trends and do not different sharply from the recent past. However, there are some investments that have been affected more than the rest.
In general, it is suggested to invest more in others for the 2018.
LS0tDQp0aXRsZTogIlRpbWUgU2VyaWVzIE1vZGVsaW5nIg0KYXV0aG9yOiAiQ2FybG9zIEVzcGVsZXRhIg0KZGF0ZTogImByIFN5cy5EYXRlKClgIg0Kb3V0cHV0OiANCiAgaHRtbF9ub3RlYm9vazogDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6IDINCiAgICB0b2NfZmxvYXQ6DQogICAgICBjb2xsYXBzZWQ6IG5vDQogICAgICBzbW9vdGhfc2Nyb2xsOiBubw0KICAgIGNvZGVfZm9sZGluZzogbm9uZQ0KICAgIHRoZW1lOiBjb3Ntbw0KICAgIGhpZ2hsaWdodDogdGFuZ28NCiAgICBjc3M6IGluY2x1ZGUvY2VudGVyLmNzcw0KICAgIGluY2x1ZGVzOg0KICAgICAgaW5faGVhZGVyOiBpbmNsdWRlL2Zhdmljb24uaHRtbA0KZWRpdG9yX29wdGlvbnM6IA0KICBtYXJrZG93bjogDQogICAgd3JhcDogOTANCi0tLQ0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldCgNCiAgd2FybmluZyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0UsIGVjaG8gPSBGQUxTRSwgDQogIGZpZy53aWR0aCA9IDcsIGZpZy5hbGlnbiA9ICJjZW50ZXIiLCANCiAgb3V0LndpZHRoID0gIjk1JSIsIGRwaSA9IDcyDQopDQpgYGANCg0KYGBge3IgbG9hZC1saWJyYXJpZXMsIGVjaG89RkFMU0V9DQojIExvYWQgcGFja2FnZXMNCmxpYnJhcnkocGxvdGx5KQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KGx1YnJpZGF0ZSkNCmxpYnJhcnkocGF0Y2h3b3JrKQ0KbGlicmFyeShmdXR1cmUpDQpsaWJyYXJ5KHRzaWJibGUpDQpsaWJyYXJ5KGZhYmxlKQ0KbGlicmFyeShnZ3RoZW1lcykNCg0KIyBBdm9pZCBtZXNzYWdlIG9uIHN1bW1hcml6ZQ0Kb3B0aW9ucyhkcGx5ci5zdW1tYXJpc2UuaW5mb3JtID0gRkFMU0UpDQoNCiMgU2V0IGRlZmF1bHQgdGhlbWUgc2V0dGluZ3MNCnRoZW1lX3NldCgNCiAgdGhlbWVfbGlnaHQoKSArDQogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpDQopDQoNCiMgRW5nbGlzaA0KaW52aXNpYmxlKFN5cy5zZXRsb2NhbGUoIkxDX0FMTCIsICJFbmdsaXNoIikpDQoNCiMgRGVmaW5lIHBhdGhzIGRpcmVjdG9yaWVzDQpwYXRoX2RhdGEgPC0gIi4uL0RhdGEiDQpwYXRoX21vZGVscyA8LSAiLi4vTW9kZWxzIg0KDQojIERlZmluZSBsYXN0IHRyYWluIGRhdGUNCmxhc3RfdHJhaW4gPC0gIjIwMTgtMDEtMDEiDQoNCiMgU2V0IFRSVUUgdG8gdHJhaW4gbW9kZWxzLCBvdGhlcndpc2Ugc2V0IHRvIEZBTFNFLg0KaXNfdHJhaW5fbW9kZWxzIDwtIEZBTFNFDQpgYGANCg0KYGBge3Iga25pdHItdGFibGUtYXV4fQ0KdG9faHRtbCA8LSBmdW5jdGlvbihkZiwgZGlnaXRzID0gMiwgLi4uKSB7DQogIGtuaXRyOjprYWJsZShkZiwgZm9ybWF0ID0gImh0bWwiLCBkaWdpdHMpICU+JSANCiAgICBrYWJsZUV4dHJhOjprYWJsZV9zdHlsaW5nKA0KICAgICAgYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwgImhvdmVyIiwgImNvbmRlbnNlZCIpLA0KICAgICAgLi4uDQogICAgKQ0KfQ0KYGBgDQoNCmBgYHtyIGxvZ28tbm92YXJ0aXMsIGVjaG89RkFMU0UsIG91dC53aWR0aD0nMTAwJSd9DQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygnLi4vSW1hZ2VzL2xvZ28tbm92YXJ0aXMucG5nJykNCmBgYA0KDQojIFRoZSBDaGFsbGVuZ2Ugey51bm51bWJlcmVkfQ0KDQpGaW5hbmNlIGhhcyB0aGUgcmVzcG9uc2liaWxpdHkgdG8gZm9yZWNhc3QsIHBsYW4gYW5kIGFsbG9jYXRlIHJlc291cmNlcyBpbiBvcmRlciB0bw0Kc3VjY2Vzc2Z1bGx5IGRlbGl2ZXIgdGhlIGJlc3QgdHJlYXRtZW50cyB0byBvdXIgcGF0aWVudHMuDQoNCi0gICBUaGUgKipmaXJzdCoqIGNoYWxsZW5nZSBjb25zaXN0IG9mIGRlbGl2ZXIgc2FsZXMgZm9yZWNhc3QgZm9yIDIwMTggcGVyIGNsdXN0ZXIsIHBlcg0KICAgIGJyYW5kIGFuZCBwZXIgbW9udGguDQoNCi0gICBUaGUgKipzZWNvbmQqKiBjaGFsbGVuZ2UgaXMgdG8gcHJvdmlkZSB0aGUgb3B0aW1hbCBhbGxvY2F0aW9uIG9mIHRoZWlyIHJlc291cmNlcyBmb3INCiAgICB0aGUgeWVhciAyMDE4Lg0KDQojIFNhbGVzIEZvcmVjYXN0aW5nDQoNClRoZSBmaXJzdCBwcm9ibGVtIGRlYWxzIHdpdGggZ2VuZXJhdGluZyB0aGUgZm9yZWNhc3RzIG9mIDc1IHRpbWUgc2VyaWVzLiBFYWNoIHRpbWUgc2VyaWVzDQpjb3JyZXNwb25kcyB0byB0aGUgZGVtYW5kIGZvciBhIHNwZWNpZmljIHByb2R1Y3QgKGJyYW5kKSBpbiBhIGdlb2dyYXBoaWMgYXJlYSAoY2x1c3RlcikuDQpUaGUgdGltZSBzZXJpZXMgYXJlIGluIG1vbnRobHkgZ3JhbnVsYXJpdHkuDQoNCldlIGhhdmUgYmVlbiBwcm92aWRlZCB3aXRoIHRoZSBkZW1hbmQgaGlzdG9yeSBmb3IgZWFjaCBvZiB0aGUgc2VyaWVzLCBzbyB0aGF0IGJ5IHRyYWluaW5nDQpzdGF0aXN0aWNhbCBtb2RlbHMgaW4gdGhlIHBhc3QsIHdlIHNob3VsZCBiZSBhYmxlIHRvIG1vZGVsIGJlaGF2aW9ycyB0aGF0IGFyZSBsaWtlbHkgdG8gYmUNCnJlcGVhdGVkIGluIHRoZSBmdXR1cmUuIFRoZXJlZm9yZSwgd2l0aCB0aW1lIHNlcmllcyBtb2RlbHMgd2Ugc2hvdWxkIGJlIGFibGUgdG8gdGFja2xlIHRoZQ0KcHJvYmxlbS4NCg0KVGhlcmUgYXJlIGRpZmZlcmVudCB0ZWNobmlxdWVzIHRvIHRhY2tsZSB0aGlzIHByb2JsZW0sIHRoZSAiYm90dG9tLXVwIiBhbmQgdGhlICJ0b3AtZG93biINCmFwcHJvYWNoLg0KDQpBIHNpbXBsZSBtZXRob2QgZm9yIGdlbmVyYXRpbmcgY29oZXJlbnQgZm9yZWNhc3RzIGlzIHRoZSAiYm90dG9tLXVwIiBhcHByb2FjaC4gVGhpcw0KYXBwcm9hY2ggaW52b2x2ZXMgZmlyc3QgZ2VuZXJhdGluZyBmb3JlY2FzdHMgZm9yIGVhY2ggc2VyaWVzIGF0IHRoZSBib3R0b20gbGV2ZWwsIGFuZCB0aGVuDQpzdW1taW5nIHRoZXNlIHRvIHByb2R1Y2UgZm9yZWNhc3RzIGZvciBhbGwgdGhlIGhpZ2hlciBsZXZlbCBzZXJpZXMuIE90aGVyIGFwcHJvYWNoZXMgYXJlDQp0aGUgInRvcC1kb3duIiB3aG9zZSBpbnZvbHZlIGZpcnN0IGdlbmVyYXRpbmcgZm9yZWNhc3RzIGZvciB0aGUgdG90YWwgc2VyaWVzLCBhbmQgdGhlbg0KZGlzYWdncmVnYXRpbmcgdGhlc2UgZG93biB0byBhbGwgdGhlIGxldmVscy4NCg0KVGhlIG1ldGhvZCBjaG9zZW4gZm9yIHRoaXMgcHJvYmxlbSBpcyB0aGUgImJvdHRvbS11cCIgYXBwcm9hY2ggYmVjYXVzZSB3aXRoIHRoaXMgbWV0aG9kIHdlDQpkbyBub3QgbG9zcyBhbnkgaW5mb3JtYXRpb24gZHVlIHRvIGFnZ3JlZ2F0aW9ucyBhbmQgYmVjYXVzZSB3aXRoIG9ubHkgNzUgc2VyaWVzIGlzIGENCmZlYXNpYmxlIGFwcHJvYWNoLg0KDQpgYGB7ciBsb2FkLWRhdGF9DQphbGxfbGV2ZWxzIDwtIHJlYWRfcmRzKGZpbGUucGF0aChwYXRoX2RhdGEsICJkYXRhX2xldmVsX3NrdS5yZHMiKSkNCmJ5X2JyYW5kIDwtIHJlYWRfcmRzKGZpbGUucGF0aChwYXRoX2RhdGEsICJkYXRhX2xldmVsX2JyYW5kLnJkcyIpKQ0KYGBgDQoNClJlY2FsbCBob3cgdGhlIGRhdGEgbG9va3MgbGlrZQ0KDQpgYGB7ciBjb252ZXJ0LXRvLXRzaWJibGV9DQojIERlZmluZSBga2V5c2AgYW5kIGBpbmRleGANCmtleSA8LSBjKCJjbHVzdGVyIiwgImJyYW5kIikNCmluZGV4IDwtICJkYXRlIg0KDQojIENvbnZlcnQgdG8gYSBgdHNpYmJsZWAgb2JqZWN0DQphbGxfbGV2ZWxzX3RibCA8LSBhbGxfbGV2ZWxzICU+JSANCiAgdW5pdGUoaWQsICEha2V5LCBzZXAgPSAiX18iLCByZW1vdmUgPSBGQUxTRSkgJT4lIA0KICBtdXRhdGUoZGF0ZSA9IHRzaWJibGU6OnllYXJtb250aCghIXN5bShpbmRleCkpKSAlPiUNCiAgYXNfdHNpYmJsZShrZXkgPSBpZCwgaW5kZXggPSBpbmRleCkNCg0KIyBQcmV2aWV3IGRhdGENCnRhaWwoYWxsX2xldmVsc190YmwsIDMpICU+JSANCiAgdG9faHRtbChkaWdpdHMgPSAxKSAlPiUgDQogIGthYmxlRXh0cmE6OnNjcm9sbF9ib3god2lkdGggPSAiMTAwJSIpDQpgYGANCg0KPGJyPg0KDQpUaGUgdHJhaW5pbmcgcHJvY2VzcyB3aWxsIGJlIGRpdmlkZWQgaW50byB0aGUgZm9sbG93aW5nIHN0ZXBzOg0KDQoxLiAgRGVmaW5lIGEgbGlzdCBvZiBtb2RlbHMgdG8gdXNlLg0KMi4gIFRyYWluIHRoZSBtb2RlbHMgdXNpbmcgdGhlIHRyYWluaW5nIGRhdGENCjMuICBDcmVhdGUgdGhlIGZvcmVjYXN0cyBmb3IgdGhlIHZhbGlkYXRpb24gZGF0YQ0KNC4gIEV2YWx1YXRlIHRoZSBwZXJmb3JtYW5jZSBvZiB0aGUgbW9kZWxzDQoNCiMjIEV2YWx1YXRpb24gbWV0cmljDQoNClRoZSBjb21wZXRpdGlvbiBtZXRyaWMgaXMgdGhlIE1lYW4gQWJzb2x1dGUgUGVyY2VudGFnZSBFcnJvciAoTUFQRSkuDQoNCiQkDQpNQVBFID0gXGZyYWN7MTAwfXtofSBcc3VtXntofV97dD0xfVxmcmFje3lfe3R9IC0gXGhhdHt5fV97dH0gfXt5X3t0fX0NCiQkDQoNCndoZXJlICR5X3QkIGlzIHRoZSBhY3R1YWwgdmFsdWUgYW5kICRcaGF0e3l9X3QkIGlzIHRoZSBwcmVkaWN0ZWQgdmFsdWUuDQoNClBlcmNlbnRhZ2UgZXJyb3JzIGhhdmUgdGhlIGFkdmFudGFnZSBvZiBiZWluZyB1bml0LWZyZWUsIGFuZCBzbyBhcmUgZnJlcXVlbnRseSB1c2VkIHRvDQpjb21wYXJlIGZvcmVjYXN0IHBlcmZvcm1hbmNlcyBiZXR3ZWVuIGRhdGEgc2V0cy4NCg0KTWVhc3VyZXMgYmFzZWQgb24gcGVyY2VudGFnZSBlcnJvcnMgaGF2ZSB0aGUgZGlzYWR2YW50YWdlIG9mIGJlaW5nIGluZmluaXRlIG9yIHVuZGVmaW5lZA0KaWYgJHlfdD0wJCBmb3IgYW55ICR0JCBpbiB0aGUgcGVyaW9kIG9mIGludGVyZXN0LCBhbmQgaGF2aW5nIGV4dHJlbWUgdmFsdWVzIGlmIGFueSAkeV90JA0KaXMgY2xvc2UgdG8gemVyby4gW01ha3JpZGFraXMgKDE5OTMpXShodHRwOi8vZHguZG9pLm9yZy8xMC4xMDE2LzAxNjktMjA3MCUyODkzJTI5OTAwNzktMykNCnNhaWQgdGhhdCAiZXF1YWwgZXJyb3JzIGFib3ZlIHRoZSBhY3R1YWwgdmFsdWUgcmVzdWx0IGluIGEgZ3JlYXRlciBBUEUgdGhhbiB0aG9zZSBiZWxvdw0KdGhlIGFjdHVhbCB2YWx1ZSIuIEhlIHByb3ZpZGVkIGFuIGV4YW1wbGUgd2hlcmUgJHlfdCA9IDE1MCQgYW5kICRcaGF0e3l9X3QgPSAxMDAkLCBzbyB0aGF0DQp0aGUgcmVsYXRpdmUgZXJyb3IgaXMgJFxmcmFjezUwfXsxNTB9ID0gMC4zMyQsIGluIGNvbnRyYXN0IHRvIHRoZSBzaXR1YXRpb24gd2hlcmUNCiR5X3QgPSAxMDAkIGFuZCAkXGhhdHt5fV90ID0gMTUwJCwgd2hlbiByZWxhdGl2ZSBlcnJvciB3b3VsZCBiZSAkXGZyYWN7NTB9ezEwMH0gPSAwLjUkLg0KVGh1cywgTUFQRSBwdXRzIGEgaGVhdmllciBwZW5hbHR5IG9uIG5lZ2F0aXZlIGVycm9ycyAod2hlbiAkeV90JCBcPCAkXGhhdHt5fV90JCkgdGhhbiBvbg0KcG9zaXRpdmUgZXJyb3JzLg0KDQpgYGB7ciBkZWZpbmUtZXZhbC1tZXRyaWN9DQptYXBlXyA8LSBmdW5jdGlvbih5X3RydWUsIHlfcHJlZCkgew0KICBtZWFuKGFicyggKHlfdHJ1ZSAtIHlfcHJlZCkgLyB5X3RydWUpKQ0KfQ0KDQpkZl8gPC0gY3Jvc3NpbmcoDQogIHlfdHJ1ZSA9IGMoMTUwLCAxMDAsIDUwKSwgDQogIGVycm9yID0gc2VxKGZyb20gPSAtMTAwLCB0byA9IDEwMCwgbGVuZ3RoLm91dCA9IDEwMCkNCiAgKSAlPiUgDQogIG11dGF0ZSgNCiAgICB5X3ByZWQgPSB5X3RydWUgKyBlcnJvciwNCiAgICBtZXRyaWNfdmFsdWUgPSBtYXAyX2RibCh5X3RydWUsIHlfcHJlZCwgbWFwZV8pDQogICkNCg0KaGlnaGxpZ2h0X2RmIDwtIGRmXyAlPiUgDQogIGdyb3VwX2J5KHlfdHJ1ZSkgJT4lIA0KICBmaWx0ZXIobWV0cmljX3ZhbHVlID09IG1heChtZXRyaWNfdmFsdWUpKSAlPiUgDQogIHNsaWNlX21heCh5X3ByZWQpICU+JSANCiAgdW5ncm91cCgpDQoNCmdncGxvdChkZl8sIGFlcyhlcnJvciwgbWV0cmljX3ZhbHVlKSkgKw0KICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAxLCBsaW5ldHlwZSA9IDIsIGFscGhhID0gMC42LCBjb2xvciA9ICJncmF5NTAiKSArDQogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDEwMCwgbGluZXR5cGUgPSAyLCBhbHBoYSA9IDAuNiwgY29sb3IgPSAiZ3JheTUwIikgKw0KICBnZW9tX2xpbmUoYWVzKGNvbG9yID0gZmFjdG9yKHlfdHJ1ZSkpKSArDQogIGdlb21fcG9pbnQoZGF0YSA9IGhpZ2hsaWdodF9kZiwgY29sb3IgPSAid2hpdGUiLCANCiAgICAgICAgICAgICBmaWxsID0gInBpbmsiLCBzaXplID0gNC41LCBzaGFwZSA9IDIxLCBhbHBoYSA9IDAuNykgKw0KICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZSA9ICJEYXJrMiIpICsNCiAgc2NhbGVfeF9jb250aW51b3VzKG4uYnJlYWtzID0gOSkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjo6cGVyY2VudCkgKw0KICAjIHRoZW1lX2ZpdmV0aGlydHllaWdodCgpICsNCiAgdGhlbWUocGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSkgKw0KICBsYWJzKHggPSAiRXJyb3IgaW4gYWJzb2x1dGUgdGVybXMiLCB5ID0gIk1BUEUiLCBjb2xvciA9ICJSZWFsIHZhbHVlIikNCmBgYA0KDQpJbiB0aGUgKngtYXhpcyogd2UgaGF2ZSB0aGUgYWJzb2x1dGUgZXJyb3IgYW5kIGluIHRoZSAqeS1heGlzKiBkZSBNQVBFLiBBYnNvbHV0ZSBlcnJvciBhcmUNCnRoZSBudW1iZXIgb2YgdW5pdHMgYWJvdmUgb3IgYmVsb3cgdGhlIHJlYWwgdmFsdWUsIGkuZSBpZiB0aGUgcmVhbCB2YWx1ZSBpcyAxMDAgYW5kIHRoZQ0KZXJyb3IgaXMgNTAgdGhlbiB0aGUgcHJlZGljdGVkIHZhbHVlIGhhcyBiZWVuIDE1MC4gRm9yIHRoZSBzYW1lIGVycm9yLCBhcyBsb3dlciB0aGUgdHJ1ZQ0KdmFsZSBpdCBpcywgdGhlIGJpZ2dlciB0aGUgZXJyb3Igd2UgaGF2ZS4NCg0KIyMgU3BsaXQgZGF0YQ0KDQpBcyB3ZSBhcmUgZGVhbGluZyB3aXRoIG1vbnRobHkgdGltZSBzZXJpZXMgZGF0YSB3ZSB3aWxsIHNwbGl0IHRoZSBzZXJpZXMgdXNpbmcgdGltZSByYXRoZXINCnRoYW4gcmFuZG9tbHkgYXMgd2UgdXN1YWxseSBkbyB3aGVuIHRyYWluaW5nIG1hY2hpbmUgbGVhcm5pbmcgbW9kZWxzLiBXZSB3aWxsIGtlZXAgYXBhcnQNCnRoZSBsYXN0IHllYXIgb2YgdGhlIGRhdGEuDQoNCmBgYHtyIHNwbGl0LWRhdGF9DQojIFRyYWluLCB2YWxpZGF0aW9uIGFuZCB0ZXN0IGV2YWx1YXRpb24NCmZpcnN0X2RhdGVfc3VibWlzc2lvbiA8LSB5ZWFybW9udGgoIjIwMTgtMDEtMDEiKQ0KbGFzdF90cmFpbiA8LSBmaXJzdF9kYXRlX3N1Ym1pc3Npb24gLSBtb250aCgxMikNCg0KdHJhaW5fZGF0YSA8LSBhbGxfbGV2ZWxzX3RibCAlPiUgDQogIGZpbHRlcihkYXRlIDwgeWVhcm1vbnRoKGxhc3RfdHJhaW4pKQ0KDQp2YWxpZF9kYXRhIDwtIGFsbF9sZXZlbHNfdGJsICU+JSANCiAgZmlsdGVyKGRhdGUgPj0geWVhcm1vbnRoKGxhc3RfdHJhaW4pLCANCiAgICAgICAgIGRhdGUgPCB5ZWFybW9udGgoZmlyc3RfZGF0ZV9zdWJtaXNzaW9uKSkNCg0KdGVzdF9kYXRhIDwtIGFsbF9sZXZlbHNfdGJsICU+JSANCiAgZmlsdGVyKGRhdGUgPj0geWVhcm1vbnRoKGZpcnN0X2RhdGVfc3VibWlzc2lvbikpDQpgYGANCg0KVGhlIGRhdGFzZXRzIHdpbGwgYmUgYXMgZm9sbG93czoNCg0KYGBge3Igc2hvdy1zcGxpdC1kYXRhLWRhdGUtcmFuZ2VzfQ0Kc3ByaW50ZigiVHJhaW4gZGF0YSBwZXJpb2Q6ICVzIC0gJXMiLCBtaW4odHJhaW5fZGF0YSRkYXRlKSwgbWF4KHRyYWluX2RhdGEkZGF0ZSkpDQpzcHJpbnRmKCJWYWxpZCBkYXRhIHBlcmlvZDogJXMgLSAlcyIsIG1pbih2YWxpZF9kYXRhJGRhdGUpLCBtYXgodmFsaWRfZGF0YSRkYXRlKSkNCnNwcmludGYoIlRlc3QgZGF0YSBwZXJpb2Q6ICVzIC0gJXMiLCBtaW4odGVzdF9kYXRhJGRhdGUpLCBtYXgodGVzdF9kYXRhJGRhdGUpKQ0KYGBgDQoNCiMjIEJhc2VsaW5lIG1vZGVscw0KDQpCZWZvcmUgZG9pbmcgbm90aGluZywgbGV0J3MgY29tcHV0ZSBzb21lIHN0YXRpc3RpY2FsIGJhc2VsaW5lcyBmb3IgYWxsIHRoZSBzZXJpZXMsIHRoYXQNCmlzLCBzdGF0aXN0aWNhbCBtb2RlbHMgdGhhdCBqdXN0IHJlcGVhdCB0aGUgbGFzdCB2YWx1ZSAoYE5BSVZFYCkgb3IgdGhlIGxhc3QgcGVyaW9kIG9mDQpzYW1wbGVzIChgU05BSVZFYCkuDQoNCmBgYHtyIHN0YXJ0LXBhcmFsbGVsaXphdGlvbiwgZWNobz1GQUxTRX0NCiMgIyBOb3Qgc3VwcG9ydGVkIG9uIFdpbmRvd3MuDQojIG15X3BsYW4gPC0gZnV0dXJlOjpwbGFuKCJtdWx0aWNvcmUiLCB3b3JrZXJzID0gNEwpDQojIGZ1dHVyZTo6cmVzZXRXb3JrZXJzKG15X3BsYW4pDQoNCiMgSSB0aGluayB0aGlzIHdvcmtzIG9uIHdpbmRvd3MNCm15X3BsYW4gPC0gZnV0dXJlOjpwbGFuKCJtdWx0aXNlc3Npb24iLCB3b3JrZXJzID0gNEwpDQojIGZ1dHVyZTo6cGxhbigic2VxdWVudGlhbCIpDQpgYGANCg0KVGhlIG1vZGVscyB0aGF0IHdlIGFyZSBnb2luZyB0byB1c2UgYXMgYSBiZW5jaG1hcmtzIGFyZToNCg0KLSAgIGBOQUlWRWA6IHRoaXMgbW9kZWwgcmVwbGljYXRlIHRoZSBsYXN0IHZhbHVlIG9mIHRoZSBzYWxlcyBkYXRhLiBUaGlzIG1vZGVsIGlzDQogICAgZXF1aXZhbGVudCB0byBhbiAkQVJJTUEoMCwxLDApJCBtb2RlbC4NCg0KLSAgIGBTTkFJVkVgOiB0aGlzIG1vZGVsIHJlcGxpY2F0ZXMgdGhlIGxhc3QgcGVyaW9kIG9mIHNhbXBsZXMgZnJvbSB0cmFpbiBkYXRhLiBUaGlzIG1vZGVsDQogICAgaXMgZXF1aXZhbGVudCB0byBhbiAkQVJJTUEoMCwwLDApKDAsMSwwKV9tJCBtb2RlbCwgd2hlcmUgKm0qIGlzIHRoZSBzZWFzb25hbCBwZXJpb2QgKG0NCiAgICA9IDEyIGluIG1vbnRobHkgZGF0YS4pDQoNCmBgYHtyIGJhc2VsaW5lLWRlZmluaXRpb24sIGVjaG89VFJVRX0NCiMgQmFzZWxpbmUgbW9kZWxzDQptb2RlbHMgPC0gbGlzdCgNCiAgbmFpdmUgICAgPSBOQUlWRShzYWxlc18yKSwNCiAgc25haXZlXzEgPSBTTkFJVkUoc2FsZXNfMiB+IGxhZygieWVhciIpICksDQogIHNuYWl2ZV8yID0gU05BSVZFKHNhbGVzXzIgfiBsYWcoInllYXIiKSArIGRyaWZ0KCkgKQ0KKQ0KYGBgDQoNCkZpdCBiYXNlbGluZSBtb2RlbHMNCg0KYGBge3IgYmFzZWxpbmUtZm9yZWNhc3QsIGVjaG89VFJVRX0NCmZpdF9iYXNlbGluZXMgPC0gdHJhaW5fZGF0YSAlPiUgDQogIG1vZGVsKCEhIW1vZGVscykNCmBgYA0KDQpHZW5lcmF0ZSBmb3JlY2FzdCBmb3IgYWxsIHRoZSBtb2RlbHMuIFRocmVlIGRpZmZlcmVudCBmb3JlY2FzdCB3aWxsIGJlIGdlbmVyYXRlZCBmb3IgZWFjaA0Kc2VyaWUuDQoNCmBgYHtyIGJhc2VsaW5lLXZhbGlkYXRpb24tZm9yZWNhc3QsIGVjaG89VFJVRX0NCmZjX2Jhc2VsaW5lcyA8LSBmaXRfYmFzZWxpbmVzICU+JSANCiAgZm9yZWNhc3QobmV3X2RhdGEgPSB2YWxpZF9kYXRhKQ0KYGBgDQoNClRoZSBtZXRyaWMgdGhhdCB3ZSB3aWxsIHVzZSB0byBldmFsdWF0ZSB0aGUgcGVyZm9ybWFuY2Ugb2YgZWFjaCBtb2RlbCBpcyB0aGUgKk1BUEUqIGJ1dCBJDQp3aWxsIGFsc28gaW5jbHVkZSB0aGUgKlJNU1NFKiBhbmQgKkNSUFMqIGZvciBjb21wbGV0ZW5lc3MuIEZvciBib3RoLCB0aGUgKlJNU0UqIGFuZCB0aGUNCipNQVBFLCogdGhlIHNtYWxsZXIgdGhlIGJldHRlci4NCg0KVGhlIGJlc3QgbW9kZWwgaGFzIGJlZW4gdGhlIGBuYWl2ZWAgd2l0aCBhICpNQVBFKiBvZiAyNi45LCBmb2xsb3dlZCBieSB0aGUgdHdvIHZhcmlhbnRzIG9mDQp0aGUgYHNuYWl2ZWAuIEFuIGVycm9yIG9mIGEgKk1BUEUqIG9mIDI2LjkgbWVhbnMgdGhhdCB0aGUgbW9kZWwgaGFzIGFuIGVycm9yIG9mIDI2LjklLg0KDQpgYGB7ciBmb3JlY2F0LWF1eC1mdW5jdGlvbnN9DQojIERlZmluZSB0aGUgbWV0cmljcyB0aGF0IHdlIHdhbnQgdG8gdXNlIHdoZW4gDQojIGV2YWx1YXRpbmcgdGhlIGZvcmVjYXN0cw0KbWVhc3VyZXMgPC0gbGlzdChSTVNTRSA9IFJNU1NFLCBNQVBFID0gTUFQRSwgQ1JQUyA9IENSUFMpDQoNCiMgRnVuY3Rpb24gdG8gcmFuayB0aGUgbW9kZWxzIGJhc2VkIG9uIGEgbWF0cmljDQphZGRfcmFuayA8LSBmdW5jdGlvbiguZGF0YSwgdmFyID0gTlVMTCkgew0KICB2YXIgPC0gc3ltKHZhcikNCiAgLmRhdGEgJT4lIA0KICAgIGdyb3VwX2J5KGlkKSAlPiUgDQogICAgbXV0YXRlKHJhbmsgPSBkZW5zZV9yYW5rKCEhdmFyKSkgJT4lIA0KICAgIHVuZ3JvdXAoKSAlPiUgDQogICAgYXJyYW5nZShpZCwgISF2YXIpDQp9DQpgYGANCg0KYGBge3IgYmFzZWxpbmUtYWNjdXJhY3l9DQojIENhbGN1bGF0ZSBhY2N1cmFjeSBmb3IgZWFjaCBzZXJpZXMgYW5kIG1vZGVsDQphY2NfYmFzZWxpbmVzIDwtIGZjX2Jhc2VsaW5lcyAlPiUgDQogIGFjY3VyYWN5KGJpbmRfcm93cyh0cmFpbl9kYXRhLCB2YWxpZF9kYXRhKSwgbWVhc3VyZXMpICU+JSANCiAgYWRkX3JhbmsodmFyID0gIk1BUEUiKQ0KDQojIEFnZ3JlZ2F0ZSBtZXRyaWNzIGJ5IGAubW9kZWxgDQphY2NfYmFzZWxpbmVzICU+JSANCiAgZ3JvdXBfYnkoLm1vZGVsKSAlPiUgDQogIHN1bW1hcmlzZV9hdCh2YXJzKFJNU1NFOkNSUFMpLCBtZWFuKSAlPiUgDQogIGFycmFuZ2UoTUFQRSkgJT4lIA0KICB0b19odG1sKGRpZ2l0cyA9IDEsIGZ1bGxfd2lkdGggPSBUUlVFKQ0KYGBgDQoNCmBgYHtyfQ0KIyAjIEJ1c2NhbW9zIGRpZmVyZW5jaWFzIGVudHJlIG1vZGVsb3MgcGFyYSBtb3N0cmFybG8gZW4gdmlzdWFsaXphY2lvbmVzDQojIGFjY19iYXNlbGluZXMgJT4lIA0KIyAgIHBpdm90X3dpZGVyKGlkX2NvbHMgPSBpZCwgbmFtZXNfZnJvbSA9IC5tb2RlbCwgdmFsdWVzX2Zyb20gPSBNQVBFKSAlPiUgDQojICAgbXV0YXRlKA0KIyAgICAgZGlmZl8xID0gYWJzKG5haXZlIC0gc25haXZlXzEpLA0KIyAgICAgZGlmZl8yID0gYWJzKHNuYWl2ZV8xIC0gc25haXZlXzIpDQojICAgKSAlPiUgDQojICAgYXJyYW5nZShkZXNjKGRpZmZfMikpICU+JSANCiMgICBoZWFkKCkNCmBgYA0KDQpOb3cgdGhhdCB3ZSBoYXZlIHRoZSBmb3JlY2FzdCBhbmQgd2Uga25vdyB3aGF0IGhhcyBiZWVuIHRoZSBiZXN0IG1vZGVsLCBsZXQncyB2aXN1YWxpemUNCnRoZSBmb3JlY2FzdCB0byBnZXQgaW5zaWdodCBpbnRvIHRoZSBkYXRhLg0KDQpgYGB7ciBhdXgtZnVuY3Rpb24tdml6LWZvcmVjYXN0c30NCnBsb3RfZm9yZWNhc3QgPC0gDQogIGZ1bmN0aW9uKGZjLCBkYXRhID0gYmluZF9yb3dzKHRyYWluX2RhdGEsIHZhbGlkX2RhdGEpLCANCiAgICAgICAgICAgZmFjZXRzID0gTlVMTCwgbGV2ZWwgPSA4MCwgbmNvbCA9IE5VTEwsIHNjYWxlcyA9ICJmaXhlZCIsIA0KICAgICAgICAgICB0aXRsZSA9IE5VTEwpIHsNCiAgICANCiAgICBpZiAoaXMubnVsbCh0aXRsZSkpIHsNCiAgICAgIHRpdGxlIDwtIHNwcmludGYoIkZvcmVjYXN0IElEOiAlcyIsIGZjJGlkW1sxXV0pDQogICAgfQ0KICAgIA0KICAgIGdnIDwtIGZjICU+JSANCiAgICAgIGF1dG9wbG90KGRhdGEsIGxldmVsID0gbGV2ZWwsIHNpemUgPSAwLjgpICsNCiAgICAgICMgZ3VpZGVzKGNvbG91ciA9IEZBTFNFKSArDQogICAgICBzY2FsZV95X2NvbnRpbnVvdXMoDQogICAgICAgIGxhYmVscyA9IHNjYWxlczo6bGFiZWxfbnVtYmVyKHN1ZmZpeCA9ICJLIiwgc2NhbGUgPSAxZS0zKQ0KICAgICAgKSArDQogICAgICBsYWJzKHN1YnRpdGxlID0gdGl0bGUsIHggPSBOVUxMLCB5ID0gTlVMTCwgY29sb3VyID0gIk1vZGVsIikgKw0KICAgICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpICsNCiAgICAgIGdndGhlbWVzOjpzY2FsZV9jb2xvcl90YWJsZWF1KHBhbGV0dGUgPSAiQ2xhc3NpYyAxMCBNZWRpdW0iKQ0KICAgIA0KICAgIGlmICghaXMubnVsbChuY29sKSkgew0KICAgICAgZ2cgPC0gZ2cgKyANCiAgICAgICAgZmFjZXRfd3JhcChmYWNldHMsIG5jb2wgPSBuY29sLCBzY2FsZXMgPSBzY2FsZXMpDQogICAgfQ0KICAgIGdnDQp9DQpgYGANCg0KQWx0aG91Z2ggdGhlIGBzbmFpdmVgIG1vZGVsIGhhcyBwZXJmb3JtZWQgYmV0dGVyIG92ZXJhbGwsIGluIHNvbWUgc2VyaWVzIGl0IHBlcmZvcm1zIHdvcnNlDQp0aGFuIHRoZSBgc25haXZlYC4NCg0KYGBge3Igdml6LWJhc2VsaW5lLWRpZmYtbmFpdmV9DQojIEJldHRlciBzbmFpdmUgdGhhbiBuYWl2ZQ0KZmNfYmFzZWxpbmVzICU+JSANCiAgZmlsdGVyKGlkID09ICJDbHVzdGVyIDdfX0JyYW5kIEdyb3VwIDMwIikgJT4lDQogIHBsb3RfZm9yZWNhc3QoZmFjZXRzID0gIi5tb2RlbCIsIG5jb2wgPSBOVUxMLCBsZXZlbCA9IE5VTEwsIHRpdGxlID0gIiIpICsNCiAgZmFjZXRfd3JhcCh+IGlkKQ0KYGBgDQoNCldlIGFsc28gZmluZCBkaWZmZXJlbmNlcyBiZXR3ZWVuIHRoZSBgc25haXZlYCBtb2RlbHMuIEluIHRoZSBmb2xsb3dpbmcgcGxvdCB3ZSBjYW4gc2VlIGhvdw0KdGhlIGBzbmFpdmVgIHdpdGggZHJpZnQgaXMgdW5kZXItZm9yZWNhc3Rpbmcgd2hpbGUgdGhlIG90aGVyLCB3aXRob3V0IGRyaWZ0LCBpcyBwcm92aWRpbmcNCmFuIGFjY2VwdGFibGUgZm9yZWNhc3QuDQoNCmBgYHtyIHZpei1iYXNlbGluZS1kaWZmLXNuYWl2ZX0NCmZjX2Jhc2VsaW5lcyAlPiUgDQogIGZpbHRlcihpZCA9PSAiQ2x1c3RlciAyX19PdGhlcnMiLCANCiAgICAgICAgIC5tb2RlbCAlaW4lIGMoInNuYWl2ZV8xIiwgInNuYWl2ZV8yIikpICU+JQ0KICBwbG90X2ZvcmVjYXN0KGZhY2V0cyA9ICIubW9kZWwiLCBuY29sID0gTlVMTCwgbGV2ZWwgPSBOVUxMLCB0aXRsZSA9ICIiKSArDQogIGZhY2V0X3dyYXAofiBpZCkNCmBgYA0KDQpTb21ldGltZXMgbm8gbW9kZWwgaXMgZ29vZC4NCg0KYGBge3Igdml6LW5haXZlLWFsbC13cm9uZ30NCmZjX2Jhc2VsaW5lcyAlPiUgDQogIGZpbHRlcihpZCA9PSAiQ2x1c3RlciA1X19CcmFuZCBHcm91cCAzMCIpICU+JQ0KICBwbG90X2ZvcmVjYXN0KGZhY2V0cyA9ICIubW9kZWwiLCBuY29sID0gTlVMTCwgbGV2ZWwgPSBOVUxMLCB0aXRsZSA9ICIiKSArDQogIGZhY2V0X3dyYXAofiBpZCkNCmBgYA0KDQojIyBTdGF0aXN0aWNhbCBCZW5jaG1hcmtzIHsjc3RhdGlzdGljYWwtYmVuY2htYXJrc30NCg0KRXhwb25lbnRpYWwgc21vb3RoaW5nIGFuZCBBUklNQSBtb2RlbHMgYXJlIHRoZSB0d28gbW9zdCB3aWRlbHkgdXNlZCBhcHByb2FjaGVzIHRvIHRpbWUNCnNlcmllcyBmb3JlY2FzdGluZywgYW5kIHByb3ZpZGUgY29tcGxlbWVudGFyeSBhcHByb2FjaGVzIHRvIHRoZSBwcm9ibGVtLiBXaGlsZSBleHBvbmVudGlhbA0Kc21vb3RoaW5nIG1vZGVscyBhcmUgYmFzZWQgb24gYSBkZXNjcmlwdGlvbiBvZiB0aGUgdHJlbmQgYW5kIHNlYXNvbmFsaXR5IGluIHRoZSBkYXRhLA0KQVJJTUEgbW9kZWxzIGFpbSB0byBkZXNjcmliZSB0aGUgYXV0b2NvcnJlbGF0aW9ucyBpbiB0aGUgZGF0YS4NCg0KLSAgIGBBUklNQWA6IGF1dG9yZWdyZXNzaXZlIGludGVncmF0ZWQgbW92aW5nIGF2ZXJhZ2UgbW9kZWwNCi0gICBgRVRTYDogZXhwb25lbnRpYWwgc21vb3RoaW5nIG1vZGVscyBhcmUgYmFzZWQgb24gYSBkZXNjcmlwdGlvbiBvZiB0aGUgdHJlbmQgYW5kDQogICAgc2Vhc29uYWxpdHkgaW4gdGhlIGRhdGENCg0KV2hlbiB0aGVyZSBhcmUgbG9uZyBzZWFzb25hbCBwZXJpb2RzLCBhIGR5bmFtaWMgcmVncmVzc2lvbiB3aXRoIGZvdXJpZXIgdGVybXMgaXMgb2Z0ZW4NCmJldHRlciB0aGFuIGBBUklNQWAgYW5kIGBFVFNgIG1vZGVscy4NCg0KRm9yIGV4YW1wbGUsIGRhaWx5IGRhdGEgY2FuIGhhdmUgYW5udWFsIHNlYXNvbmFsaXR5IG9mIGxlbmd0aCAzNjUsIHdlZWtseSBkYXRhIGhhcw0Kc2Vhc29uYWwgcGVyaW9kIG9mIGFwcHJveGltYXRlbHkgNTIsIHdoaWxlIGhhbGYtaG91cmx5IGRhdGEgY2FuIGhhdmUgc2V2ZXJhbCBzZWFzb25hbA0KcGVyaW9kcywgdGhlIHNob3J0ZXN0IG9mIHdoaWNoIGlzIHRoZSBkYWlseSBwYXR0ZXJuIG9mIHBlcmlvZCA0OC4NCg0KRGVzcGl0ZSB3ZSBkbyBub3QgaGF2ZSBsb25nIHNlYXNvbmFsIHBlcmlvZHMgaGVyZSwgdGhpcyBtb2RlbHMgd2lsbCBiZSBpbmNsdWRlZCBpbiBvdXINCmxpc3Qgb2YgbW9kZWxzLg0KDQotICAgYEZPVVJJRVJgOiBMaW5lYXIgcmVncmVzc2lvbiBtb2RlbCB3aXRoIGVycm9ycyBtb2RlbGVkIHdpdGggYW4gYXJpbWEgbW9kZWwgdG8gcmVtb3ZlDQogICAgdGhlIGF1dG9jb3JyZWxhdGlvbi4NCg0KQWRkaXRpb25hbGx5IHRvIHRoaXMgbW9kZWxzLCBpdCBoYXMgYWxzbyBiZWVuIGluY2x1ZGVkIGEgY29tYmluYXRpb24gZm9yZWNhc3Qgb2YgYEFSSU1BYA0KYW5kIGBFVFNgIG1vZGVscyB3aGljaCBoYXMgYmVlbiBjYWxsZWQgYGNvbWJuYC4NCg0KYGBge3Igc3RhdGlzdGljYWwtZGVmaW5pdGlvbiwgZWNobz1UUlVFfQ0KbW9kZWxzX3N0YXQgPC0gbGlzdCgNCiAgIyBTdGF0aXN0aWNhbCBiZW5jaG1hcmtzDQogIGFyaW1hID0gQVJJTUEoc2FsZXNfMiksDQogIGV0cyAgID0gRVRTKHNhbGVzXzIpLA0KICANCiAgIyBVc2luZyBGb3VyaWVyIHRlcm1zIGFuZCBBUklNQSBlcnJvcnMgZm9yIGZvcmVjYXN0aW5nDQogIGBLID0gMWAgPSBBUklNQShzYWxlc18yIH4gZm91cmllcihLID0gMSkgKyBQRFEoMCwgMCwgMCkpLA0KICBgSyA9IDJgID0gQVJJTUEoc2FsZXNfMiB+IGZvdXJpZXIoSyA9IDIpICsgUERRKDAsIDAsIDApKSwNCiAgYEsgPSAzYCA9IEFSSU1BKHNhbGVzXzIgfiBmb3VyaWVyKEsgPSAzKSArIFBEUSgwLCAwLCAwKSksDQogIGBLID0gNGAgPSBBUklNQShzYWxlc18yIH4gZm91cmllcihLID0gNCkgKyBQRFEoMCwgMCwgMCkpLA0KICBgSyA9IDVgID0gQVJJTUEoc2FsZXNfMiB+IGZvdXJpZXIoSyA9IDUpICsgUERRKDAsIDAsIDApKSwNCiAgYEsgPSA2YCA9IEFSSU1BKHNhbGVzXzIgfiBmb3VyaWVyKEsgPSA2KSArIFBEUSgwLCAwLCAwKSkNCikNCmBgYA0KDQpgYGB7ciBmaXQtc3RhdGlzdGljYWwtbW9kZWxzLCBldmFsPWlzX3RyYWluX21vZGVsc30NCiMgVHJhaW4gbW9kZWxzDQpmaXRfc3RhdGlzdGljYWwgPC0gdHJhaW5fZGF0YSAlPiUgDQogIG1vZGVsKCEhIW1vZGVsc19zdGF0KSAlPiUgDQogIG11dGF0ZShjb21ibiA9IChhcmltYSArIGV0cykgLyAyKQ0KDQojIFNhdmUgbW9kZWxzDQp3cml0ZV9yZHMoZml0X3N0YXRpc3RpY2FsLCANCiAgZmlsZS5wYXRoKHBhdGhfbW9kZWxzLCAiZml0X3N0YXRpc3RpY2FsLnJkcyIpLCANCiAgY29tcHJlc3MgPSAiZ3oiKQ0KDQojIEdlbmVyYXRlIGZvcmVjYXN0cyBmb3IgdGhlIHZhbGlkYXRpb24gcGVyaW9kDQpmY19zdGF0aXN0aWNhbCA8LSBmaXRfc3RhdGlzdGljYWwgJT4lIA0KICBmb3JlY2FzdChuZXdfZGF0YSA9IHZhbGlkX2RhdGEpDQoNCiMgU2F2ZSBmb3JlY2FzdHMNCndyaXRlX3JkcyhmY19zdGF0aXN0aWNhbCwgDQogIGZpbGUucGF0aChwYXRoX21vZGVscywgImZjX3N0YXRpc3RpY2FsLnJkcyIpLCANCiAgY29tcHJlc3MgPSAiZ3oiKQ0KYGBgDQoNCmBgYHtyIHN0YXRpc3RpY2FsLWZvcmVjYXN0LWdlbmVyYXRpb259DQojIExvYWQgbW9kZWxzDQpmaXRfc3RhdGlzdGljYWwgPC0gcmVhZF9yZHMoZmlsZS5wYXRoKHBhdGhfbW9kZWxzLCAiZml0X3N0YXRpc3RpY2FsLnJkcyIpKQ0KDQojIExvYWQgZm9yZWNhc3RzDQpmY19zdGF0aXN0aWNhbCA8LSByZWFkX3JkcyhmaWxlLnBhdGgocGF0aF9tb2RlbHMsICJmY19zdGF0aXN0aWNhbC5yZHMiKSkNCg0KIyBDYWxjdWxhdGUgYWNjdXJhY3kgZm9yIGVhY2ggc2VyaWVzIGFuZCBtb2RlbA0KYWNjX3N0YXRpc3RpY2FsIDwtIGZjX3N0YXRpc3RpY2FsICU+JSANCiAgYWNjdXJhY3koYmluZF9yb3dzKHRyYWluX2RhdGEsIHZhbGlkX2RhdGEpLCBtZWFzdXJlcykgJT4lIA0KICBhZGRfcmFuayh2YXIgPSAiTUFQRSIpDQpgYGANCg0KVGhlIGJlc3QgbW9kZWwgaXMgdGhlIGBjb21ibmAsIGZvbGxvd2VkIGJ5IHRoZSBgQVJJTUFgIGFuZCB0aGUgYEsgPSAyYCBtb2RlbHMuIFRoZSBlcnJvcg0KaGFzIGJlZW4gcmVkdWNlZCBieSAyNi40JSB3aXRoIHJlc3BlY3QgdG8gdGhlIGBuYWl2ZWAgbW9kZWwuDQoNCmBgYHtyIG1vZGVsLXJlZHVjdGlvbi1wZXJjZW50YWdlLCBlY2hvPUZBTFNFLCBldmFsPUZBTFNFfQ0Kbm4gPC0gMjYuOSAgICAjIG5haXZlIG1vZGVsDQpjYyA8LSAxOS44ICAgICMgY29tYm4gbW9kZWwNCihjYyAvIG5uKSAtIDEgIyByZWR1Y3Rpb24gcGVyY2VudGFnZQ0KIyBbMV0gLTAuMjYzOTQwNQ0KYGBgDQoNCmBgYHtyIHN0YXRpc3RpY2FsLWFjY3VyYWN5fQ0KIyBBZ2dyZWdhdGUgbWV0cmljcyBieSBgLm1vZGVsYA0KYWNjX3N0YXRpc3RpY2FsICU+JSANCiAgZ3JvdXBfYnkoLm1vZGVsKSAlPiUgDQogIHN1bW1hcmlzZV9hdCh2YXJzKFJNU1NFOkNSUFMpLCBtZWFuKSAlPiUgDQogIGFycmFuZ2UoTUFQRSkgJT4lIA0KICBoZWFkKDYpICU+JSANCiAgdG9faHRtbChkaWdpdHMgPSAxKQ0KYGBgDQoNCmBgYHtyfQ0KIyAjIERvZXMgYWxsIHRoZSBicmFuZHMgcGVyZm9ybSBlcXVhbGx5PyBJcyBhbHdheXMgdGhlIHNhbWUgbW9kZWwgdGhlIGJlc3QgcGVyZm9ybWVyPw0KIyBhY2Nfc3RhdGlzdGljYWwgJT4lIA0KIyAgIHNlcGFyYXRlKGlkLCBpbnRvID0gYygiY2x1c3RlciIsICJicmFuZCIpLCBzZXAgPSAiX18iKSAlPiUgDQojICAgZ3JvdXBfYnkoYnJhbmQsIC5tb2RlbCkgJT4lIA0KIyAgIHN1bW1hcmlzZV9hdCh2YXJzKFJNU1NFOkNSUFMpLCBtZWFuKSAlPiUgDQojICAgYXJyYW5nZShNQVBFKSAlPiUgDQojICAgc2xpY2UoMSkgJT4lIA0KIyAgIHRvX2h0bWwoZGlnaXRzID0gMSkNCmBgYA0KDQpJbiB0aGUgZXhhbXBsZSBiZWxvdywgbmVpdGhlciBtb2RlbCBoYXMgZ2VuZXJhdGVkIGEgZ29vZCBmb3JlY2FzdCwgaW4gZmFjdCwgaXQgc2VlbXMgdGhhdA0KdGhlIGBldHNgIG1vZGVsIG9ubHkgaGFzIGNhcHR1cmVkIHRoZSB0cmVuZC4NCg0KYGBge3Igdml6LXN0YXQtZm9yZWNhc3QtMDF9DQpmY19zdGF0aXN0aWNhbCAlPiUNCiAgZmlsdGVyKA0KICAgIGlkID09ICJDbHVzdGVyIDdfX0JyYW5kIEdyb3VwIDMwIiwNCiAgICAubW9kZWwgJWluJSBjKCJhcmltYSIsICJldHMiKQ0KICApICU+JQ0KICBwbG90X2ZvcmVjYXN0KGZhY2V0cyA9ICIubW9kZWwiLCBuY29sID0gTlVMTCwgbGV2ZWwgPSBOVUxMLCB0aXRsZSA9ICIiKSArDQogIGZhY2V0X3dyYXAofiBpZCkNCmBgYA0KDQpJbiB0aGlzIG90aGVyIGNhc2UsIGJvdGggZm9yZWNhc3RzIGFyZSBzaW1pbGFyIHRvIGVhY2ggb3RoZXIgYW5kIHRoZSBgc25haXZlXzFgDQoNCmBgYHtyIHZpei1zdGF0LWZvcmVjYXN0LTAyfQ0KZmNfc3RhdGlzdGljYWwgJT4lIA0KICBmaWx0ZXIoDQogICAgaWQgPT0gIkNsdXN0ZXIgMl9fT3RoZXJzIiwgDQogICAgLm1vZGVsICVpbiUgYygiZXRzIiwgImFyaW1hIikNCiAgKSAlPiUNCiAgcGxvdF9mb3JlY2FzdChmYWNldHMgPSAiLm1vZGVsIiwgbmNvbCA9IE5VTEwsIGxldmVsID0gTlVMTCwgdGl0bGUgPSAiIikgKw0KICBmYWNldF93cmFwKH4gaWQpDQpgYGANCg0KQWdhaW4sIG5vbmUgb2YgdGhlIG1vZGVscyBoYXMgYmVlbiBhYmxlIHRvIGNhcHR1cmUgdGhlIGJpZyBkcm9wIG9mZiBvZiAyMDE3Lg0KDQpgYGB7ciB2aXotc3RhdGlzdGljYWwtYWxsLXdyb25nfQ0KZmNfc3RhdGlzdGljYWwgJT4lIA0KICBmaWx0ZXIoDQogICAgaWQgPT0gIkNsdXN0ZXIgNV9fQnJhbmQgR3JvdXAgMzAiDQogICkgJT4lDQogIHBsb3RfZm9yZWNhc3QoZmFjZXRzID0gIi5tb2RlbCIsIG5jb2wgPSBOVUxMLCBsZXZlbCA9IE5VTEwsIHRpdGxlID0gIiIpICsNCiAgZmFjZXRfd3JhcCh+IGlkKQ0KYGBgDQoNCiMjIEV4dGVybmFsIEluZm9ybWF0aW9uDQoNClRoZSB0aW1lIHNlcmllcyBtb2RlbHMgdXNlZCBzbyBmYXIgYWxsb3cgZm9yIHRoZSBpbmNsdXNpb24gb2YgaW5mb3JtYXRpb24gZnJvbSBwYXN0DQpvYnNlcnZhdGlvbnMgb2YgYSBzZXJpZXMsIGJ1dCBub3QgZm9yIHRoZSBpbmNsdXNpb24gb2Ygb3RoZXIgaW5mb3JtYXRpb24gdGhhdCBtYXkgYWxzbyBiZQ0KcmVsZXZhbnQuIEZvciBleGFtcGxlLCB0aGUgZWZmZWN0cyBvZiB0aGUgaW52ZXN0bWVudHMgbWF5IGV4cGxhaW4gc29tZSBvZiB0aGUgaGlzdG9yaWNhbA0KdmFyaWF0aW9uIGFuZCBtYXkgbGVhZCB0byBtb3JlIGFjY3VyYXRlIGZvcmVjYXN0cw0KDQpgYGB7ciB4cmVnLWRlZmluaXRpb24sIGVjaG89VFJVRX0NCiMgVXNpbmcgaW52ZXN0bWVudHMgYXMgcHJlZGljdG9ycw0KbW9kZWxzX3hyZWcgPC0gbGlzdCgNCiAgeHJlZ18xID0gQVJJTUEoc2FsZXNfMiB+IGludmVzdG1lbnRfMSksDQogIHhyZWdfMiA9IEFSSU1BKHNhbGVzXzIgfiBpbnZlc3RtZW50XzEgKyBpbnZlc3RtZW50XzIpLA0KICB4cmVnXzMgPSBBUklNQShzYWxlc18yIH4gaW52ZXN0bWVudF8xICsgaW52ZXN0bWVudF8yICsgaW52ZXN0bWVudF8zKSwNCiAgeHJlZ180ID0gQVJJTUEoc2FsZXNfMiB+IGludmVzdG1lbnRfMSArIGludmVzdG1lbnRfMiArIGludmVzdG1lbnRfMyArIA0KICAgICAgICAgICAgICAgICAgIGludmVzdG1lbnRfNCArIGludmVzdG1lbnRfNSArIGludmVzdG1lbnRfNikNCikNCmBgYA0KDQpgYGB7ciB0cmFpbi1tb2RlbHMteHJlZywgZXZhbD1pc190cmFpbl9tb2RlbHN9DQojIFRyYWluIG1vZGVscw0KZml0X3hyZWdfIDwtIHRyYWluX2RhdGEgJT4lIA0KICBtb2RlbCghISFtb2RlbHNfeHJlZykNCg0KIyBBcHBlbmQgQVJJTUEgbW9kZWxzIGFzIGRlZmF1bHQgaW4gY2FzZSBvZiBmYWlsdXJlDQojIFJlcGxhY2UgTlVMTCBtb2RlbHMgYnkgYSBgZGVmYXVsdGAgbW9kZWwNCmZpdF94cmVnIDwtIGZpdF94cmVnXyAlPiUgDQogIGxlZnRfam9pbigNCiAgICBzZWxlY3QoZml0X3N0YXRpc3RpY2FsLCBpZCwgZGVmYXVsdCA9IGFyaW1hKSwgDQogICAgYnkgPSAiaWQiDQogICkgJT4lIA0KICBtdXRhdGUoYWNyb3NzKGNvbnRhaW5zKCJ4cmVnIiksIH4gaWZfZWxzZShpc19udWxsX21vZGVsKC54KSwgZGVmYXVsdCwgLngpICkpICU+JSANCiAgIyBEcm9wIGRlZmF1bHQgbW9kZWwNCiAgc2VsZWN0KC1kZWZhdWx0KQ0KDQojIFNhdmUgbW9kZWxzDQp3cml0ZV9yZHMoZml0X3hyZWcsIA0KICBmaWxlLnBhdGgocGF0aF9tb2RlbHMsICJmaXRfeHJlZy5yZHMiKSwgDQogIGNvbXByZXNzID0gImd6IikNCg0KIyBHZW5lcmF0ZSBmb3JlY2FzdHMgZm9yIHRoZSB2YWxpZGF0aW9uIHBlcmlvZA0KZmNfeHJlZyA8LSBmaXRfeHJlZyAlPiUgDQogIGZvcmVjYXN0KG5ld19kYXRhID0gdmFsaWRfZGF0YSkNCg0KIyBTYXZlIGZvcmVjYXN0cw0Kd3JpdGVfcmRzKGZjX3hyZWcsIA0KICBmaWxlLnBhdGgocGF0aF9tb2RlbHMsICJmY194cmVnLnJkcyIpLCANCiAgY29tcHJlc3MgPSAiZ3oiKQ0KYGBgDQoNCmBgYHtyIGxvYWQteHJlZy1tb2RlbHN9DQojIExvYWQgbW9kZWxzDQpmaXRfeHJlZyA8LSByZWFkX3JkcyhmaWxlLnBhdGgocGF0aF9tb2RlbHMsICJmaXRfeHJlZy5yZHMiKSkNCg0KIyBMb2FkIGZvcmVjYXN0cw0KZmNfeHJlZyA8LSByZWFkX3JkcyhmaWxlLnBhdGgocGF0aF9tb2RlbHMsICJmY194cmVnLnJkcyIpKQ0KDQojIENhbGN1bGF0ZSBhY2N1cmFjeSBmb3IgZWFjaCBzZXJpZXMgYW5kIG1vZGVsDQphY2NfeHJlZyA8LSBmY194cmVnICU+JSANCiAgYWNjdXJhY3koYmluZF9yb3dzKHRyYWluX2RhdGEsIHZhbGlkX2RhdGEpLCBtZWFzdXJlcykgJT4lIA0KICBhZGRfcmFuayh2YXIgPSAiTUFQRSIpDQpgYGANCg0KT3ZlcmFsbCBhY2N1cmFjeSBpcyBub3QgYXMgZ29vZCBhcyBgY29tYm5gLCBgYXJpbWFgIG9yYGV0c2AgbW9kZWxzIHRyYWluZWQgb24gW3N0YXRpc3RpY2FsDQpiZW5jaG1hcmtzXSgjc3RhdGlzdGljYWwtYmVuY2htYXJrcykgc2VjdGlvbi4NCg0KYGBge3IgYWNjLXhyZWctbW9kZWxzfQ0KIyBBZ2dyZWdhdGUgbWV0cmljcyBieSBgLm1vZGVsYA0KYWNjX3hyZWcgJT4lIA0KICBncm91cF9ieSgubW9kZWwpICU+JSANCiAgc3VtbWFyaXNlX2F0KHZhcnMoUk1TU0U6Q1JQUyksIG1lYW4pICU+JSANCiAgYXJyYW5nZShNQVBFKSAlPiUgDQogIHRvX2h0bWwoZGlnaXRzID0gMSkNCmBgYA0KDQpNb2RlbCBgSyA9IDRgIG92ZXJmaXQgdGhlIGRhdGEgYW5kIGdlbmVyYXRlIGEgZm9yZWNhc3QgaW4gdGhlIG9wcG9zaXRlIGRpcmVjdGlvbi4gSW4NCmNvbnRyYXN0LCB0aGUgYEsgPSAyYCBpcyBhYmxlIHRvIGNhcHR1cmUgYSBtb3JlIGdlbmVyYWwgcGF0dGVybi4gVGhpcyBpcyBhIGdvb2QgZXhhbXBsZQ0KdGhhdCBtb3JlIGNvbXBsZXggbW9kZWxzIGRvIG5vdCBhbHdheXMgaW5kaWNhdGUgYmV0dGVyIHJlc3VsdHMuDQoNCmBgYHtyIHZpei14cmVnLW1vZGVscy0wMX0NCmZjX3hyZWcgJT4lDQogIGZpbHRlcigNCiAgICBpZCA9PSAiQ2x1c3RlciA3X19CcmFuZCBHcm91cCAzMCIsDQogICAgLm1vZGVsICVpbiUgYygieHJlZ18yIiwgInhyZWdfNCIpDQogICkgJT4lDQogIHBsb3RfZm9yZWNhc3QoZmFjZXRzID0gIi5tb2RlbCIsIG5jb2wgPSBOVUxMLCBsZXZlbCA9IE5VTEwsIHRpdGxlID0gIiIpICsNCiAgbGFicyh0aXRsZSA9IE5VTEwpICsNCiAgZmFjZXRfd3JhcCh+IGlkKQ0KYGBgDQoNCkFsbCB0aGUgZm9yZWNhc3RzIGFyZSBxdWl0ZSBzaW1pbGFyIGluIHRoaXMgY2FzZQ0KDQpgYGB7ciB2aXoteHJlZy1tb2RlbHMtMDJ9DQpmY194cmVnICU+JSANCiAgZmlsdGVyKGlkID09ICJDbHVzdGVyIDJfX090aGVycyIpICU+JQ0KICBwbG90X2ZvcmVjYXN0KGZhY2V0cyA9ICIubW9kZWwiLCBuY29sID0gTlVMTCwgbGV2ZWwgPSBOVUxMLCB0aXRsZSA9ICIiKSArDQogIGZhY2V0X3dyYXAofiBpZCkNCmBgYA0KDQpBcHBhcmVudGx5LCB0aGUgaW52ZXN0bWVudHMgbmVpdGhlciBleHBsYWluIHRoZSBkcm9wIG9mZiBvZiAyMDE3Lg0KDQpgYGB7ciB2aXoteHJlZy1tb2RlbHMtMDN9DQpmY194cmVnICU+JSANCiAgZmlsdGVyKGlkID09ICJDbHVzdGVyIDVfX0JyYW5kIEdyb3VwIDMwIikgJT4lDQogIHBsb3RfZm9yZWNhc3QoZmFjZXRzID0gIi5tb2RlbCIsIG5jb2wgPSBOVUxMLCBsZXZlbCA9IE5VTEwsIHRpdGxlID0gIiIpICsNCiAgZmFjZXRfd3JhcCh+IGlkKQ0KYGBgDQoNCkZvciBjYXNlcyBsaWtlIHRoaXMsIHdlIGFyZSBnb2luZyB0byBpbnRyb2R1Y2UgYSBuZXcgc2V0IG9mIG1vZGVscyB0aGF0IHdpbGwgaGVscCB1cyB0bw0KaW1wcm92ZSB0aGlzIHN0cnVjdHVyYWwgY2hhbmdlcy4NCg0KYGBge3IgZnV0dXJlLXBsYW4tc2VxdWVudGlhbH0NCmZ1dHVyZTo6cGxhbigic2VxdWVudGlhbCIpDQpgYGANCg0KIyMgUGllY2V3aXNlIHJlZ3Jlc3Npb24NCg0KV2UgaGF2ZSBzZWVuIHRoYXQsIGluIHNvbWUgY2FzZXMsIHRoZSB0cmVuZCBpcyBub3QgbGluZWFyIGFuZCB0aGUgbW9kZWxzIGFyZSBub3QgYWJsZSB0bw0KbW9kZWwgdGhlIHNlcmllcyBjb3JyZWN0bHkuIFBpZWNlLXdpc2UgbW9kZWxzIGRpdmlkZSB0aGUgc2VyaWVzIGludG8gc2V2ZXJhbCBzZWdtZW50cyBpbg0Kc3VjaCBhIHdheSB0aGF0IHRoZXkgYXJlIGFibGUgdG8gZGV0ZWN0IHRoZSB0cmVuZCBjb3JyZWN0bHkuDQoNCiMjIyBCcmFuZCBhbmFseXNpcw0KDQpQZXJmb3JtaW5nIHRoZSBhbmFseXNpcyBmb3IgZWFjaCBzZXJpZXMgaXMgYSBjb21wbGljYXRlZCBhbmQgdGltZS1jb25zdW1pbmcgdGFzay4gRm9yIHRoaXMNCnJlYXNvbiwgbWFueSB0aW1lcyBoaWdoZXIgbGV2ZWxzIG9mIGFnZ3JlZ2F0aW9uIGFyZSBhbmFseXplZCBhbmQgdGhlbiB0aGVzZSBjb25kaXRpb25zIG9yDQpwYXJhbWV0ZXJzIGFyZSBhcHBsaWVkIHRvIGxvd2VyIGxldmVscyBzZXJpZXMuDQoNCmBgYHtyIGJyYW5kLXRpYmJsZS10by10c2liYmxlfQ0KYnlfYnJhbmRfdHNpYmJsZSA8LSBieV9icmFuZCAlPiUgDQogIGZpbHRlcihkYXRlIDwgYXMuRGF0ZShsYXN0X3RyYWluKSkgJT4lIA0KICBtdXRhdGUoZGF0ZSA9IHRzaWJibGU6OnllYXJtb250aCghIXN5bShpbmRleCkpKSAlPiUNCiAgYXNfdHNpYmJsZShrZXkgPSBicmFuZCwgaW5kZXggPSBkYXRlKQ0KYGBgDQoNClRoZSBwbG90IG9mIHRoZSAqQnJhbmQgR3JvdXAgMzEqIHJldmVhbHMgdHdvIGRpZmZlcmVudCBwZXJpb2RzLiBUaGVyZSBpcyBhIGNsZWFyIHVwdHJlbmQNCnVwIHRvIHRoZSBlbmQgb2YgMjAxNS4gQWZ0ZXIgMjAxNSB0aGVyZSBpcyBhIGRlY3JlYXNlIGluIHRoZSBncm93aW5nIHNwZWVkIGFuZCB0aGUgdHJlbmQNCnNsb3cgZG93biBhIGJpdC4gVG8gYWNjb3VudCBmb3IgdGhlc2UgY2hhbmdlcywgd2Ugc3BlY2lmeSB0aGUgZGF0ZSAqMjAxNS0wMSogYXMga25vdHMuDQoNCmBgYHtyIGZpdC1tb2RlbC1icmFuZC0zMSwgZWNobz1UUlVFfQ0KIyBTZWxlY3QgYSBicmFuZCBhIGZpdCBhIG1vZGVsDQpjdXJyZW50X2JyYW5kIDwtICJCcmFuZCBHcm91cCAzMSINCg0KIyBGaXQgc2ltcGxlIGBsbWAgYW5kIGBwaWVjZXdpc2VgIG1vZGVsDQpmaXRfdHJlbmRzIDwtIGJ5X2JyYW5kX3RzaWJibGUgJT4lIA0KICBmaWx0ZXIoYnJhbmQgPT0gY3VycmVudF9icmFuZCkgJT4lIA0KICBtb2RlbCgNCiAgICBsbSA9IFRTTE0oc2FsZXNfMiB+IHRyZW5kKCkpLA0KICAgIHBpZWNld2lzZSA9IFRTTE0oc2FsZXNfMiB+IHRyZW5kKA0KICAgICAga25vdHMgPSB0c2liYmxlOjp5ZWFybW9udGgoIjIwMTUtMDEiKSkpDQogICkNCmBgYA0KDQpgYGB7ciB2aXotdHNsbS10cmVuZH0NCmZjX3RyZW5kcyA8LSBmaXRfdHJlbmRzICU+JSANCiAgZm9yZWNhc3QoaCA9IDEyKQ0KDQpmaXRfdHJlbmRzICU+JSANCiAgYXVnbWVudCgpICU+JSANCiAgZ2dwbG90KGFlcyh4ID0gZGF0ZSkpICsNCiAgZ2VvbV9saW5lKGFlcyh5ID0gc2FsZXNfMiksIGNvbG91ciA9ICJibGFjayIpICsNCiAgZ2VvbV9saW5lKGFlcyh5ID0gLmZpdHRlZCwgY29sb3VyID0gLm1vZGVsKSwgc2l6ZSA9IDEpICsNCiAgc2NhbGVfY29sb3JfYnJld2VyKHBhbGV0dGUgPSAiU2V0MiIsIGRpcmVjdGlvbiA9IC0xKSArDQogIHNjYWxlX3lfY29udGludW91cygNCiAgICBsYWJlbHMgPSBzY2FsZXM6OmxhYmVsX251bWJlcihzdWZmaXggPSAiSyIsIHNjYWxlID0gMWUtMykNCiAgKSArDQogIGF1dG9sYXllcihmY190cmVuZHMsIGFscGhhID0gMC4zLCBsZXZlbCA9IDkwKSArDQogIGxhYnMoDQogICAgeCA9IE5VTEwsIHkgPSBOVUxMLA0KICAgIHRpdGxlID0gIk9yaWdpbmFsIHZhbHVlcyBhbmQgZml0dGVkIHRyZW5kIiwgDQogICAgc3VidGl0bGUgPSBjdXJyZW50X2JyYW5kDQogICkNCmBgYA0KDQpJbiB0aGUgcGxvdCBiZWxvdyB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlIHJlYWwgYW5kIGFkanVzdGVkIHZhbHVlcyBieSB0aGUgbW9kZWwgaXMNCnNob3duLiBUaGUgc2xhc2hlZCBsaW5lIHJlcHJlc2VudHMgdGhlIHBlcmZlY3Rpb24sIGluIHN1Y2ggYSB3YXkgdGhhdCB0aGUgZnVydGhlciB0aGUNCnBvaW50cyBhcmUgZnJvbSB0aGUgbGluZSwgdGhlIHdvcnNlIHRoZSBtb2RlbCBpcy4gSW4gdGhlIGxvd2VyIGxlZnQgY29ybmVyLCB0aGUgdmFsdWVzIG9mDQp0aGUgYHBpZWNld2lzZWAgbW9kZWwgYXJlIG11Y2ggYmV0dGVyIGFkanVzdGVkIHRvIHRoZSByZWFsaXR5IHdoaWxlIHRob3NlIG9mIHRoZSBgbG1gIGFyZQ0KZmFydGhlciBhd2F5LiBJbiBnZW5lcmFsLCB0aGVyZSBpcyBhIGJpZ2dlciBkaXNwZXJzaW9uIGluIHRoZSBgbG1gIG1vZGVsIHRoYW4gaW4gdGhlDQpgcGllY2V3aXNlYC4NCg0KYGBge3IgZml0dGVkLXZzLXJlYWwtdmFsdWVzfQ0KZml0X3RyZW5kcyAlPiUgDQogIGF1Z21lbnQoKSAlPiUgDQogIGdncGxvdChhZXMoeCA9IHNhbGVzXzIsIHkgPSAuZml0dGVkKSkgKw0KICBnZW9tX3BvaW50KGFlcyhmaWxsID0gLm1vZGVsKSwgc2hhcGUgPSAyMSwgc2l6ZSA9IDIpICsNCiAgc2NhbGVfeF9jb250aW51b3VzKA0KICAgIGxhYmVscyA9IHNjYWxlczo6bGFiZWxfbnVtYmVyKHN1ZmZpeCA9ICJLIiwgc2NhbGUgPSAxZS0zKQ0KICApICsNCiAgc2NhbGVfeV9jb250aW51b3VzKA0KICAgIGxhYmVscyA9IHNjYWxlczo6bGFiZWxfbnVtYmVyKHN1ZmZpeCA9ICJLIiwgc2NhbGUgPSAxZS0zKQ0KICApICsNCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJTZXQyIiwgZGlyZWN0aW9uID0gLTEpICsNCiAgZ2VvbV9hYmxpbmUoaW50ZXJjZXB0ID0gMCwgc2xvcGUgPSAxLCBsaW5ldHlwZSA9IDIpICsNCiAgbGFicygNCiAgICB4ID0gIkRhdGEgKG9yaWdpbmFsIHNhbGVzKSIsIA0KICAgIHkgPSAiRml0dGVkIChwcmVkaWN0ZWQgdmFsdWVzKSIsDQogICAgdGl0bGUgPSAiT3JpZ2luYWwgdmFsdWVzIGFuZCBmaXR0ZWQgdHJlbmQiLCANCiAgICBzdWJ0aXRsZSA9IGN1cnJlbnRfYnJhbmQNCiAgKQ0KYGBgDQoNCmBgYHtyIHBpZWNld2lzZS1tb2RlbC1kZWZpbml0aW9ufQ0KZ2V0X21vZGVscyA8LSBmdW5jdGlvbihicmFuZCkgew0KICANCiAgIyBEZWZpbmUgc3RlcC13aXNlIG1vZGVscw0KICBtZGwgPC0gbnVsbF9tb2RlbCgpDQogIGlmIChicmFuZCA9PSAiQnJhbmQgR3JvdXAgMTciKSB7DQogICAgbWRsICA8LSBUU0xNKHNhbGVzXzIgfiB0cmVuZChrbm90cyA9IHRzaWJibGU6OnllYXJtb250aCgiMjAxNS0wMyIpKSArIHNlYXNvbigpKQ0KICB9IGVsc2UgaWYgKGJyYW5kID09ICJCcmFuZCBHcm91cCAyNCIpIHsNCiAgICBtZGwgIDwtIFRTTE0oc2FsZXNfMiB+IHRyZW5kKGtub3RzID0gdHNpYmJsZTo6eWVhcm1vbnRoKCIyMDE1LTEwIikpICsgc2Vhc29uKCkpDQogIH0gZWxzZSBpZiAoYnJhbmQgPT0gIkJyYW5kIEdyb3VwIDMwIikgew0KICAgIG1kbCAgPC0gVFNMTShzYWxlc18yIH4gdHJlbmQoDQogICAgICBrbm90cyA9IGModHNpYmJsZTo6eWVhcm1vbnRoKCIyMDEzLTA3IiksIHRzaWJibGU6OnllYXJtb250aCgiMjAxNi0wMSIpKQ0KICAgICAgKSArIHNlYXNvbigpICkNCiAgfSBlbHNlIGlmIChicmFuZCA9PSAiQnJhbmQgR3JvdXAgMzEiKSB7DQogICAgbWRsICA8LSBUU0xNKHNhbGVzXzIgfiB0cmVuZChrbm90cyA9IHRzaWJibGU6OnllYXJtb250aCgiMjAxNS0wMSIpKSArIHNlYXNvbigpKQ0KICB9IGVsc2UgaWYgKGJyYW5kID09ICJCcmFuZCBHcm91cCAzNiIpIHsNCiAgICBtZGwgIDwtIFRTTE0oc2FsZXNfMiB+IHRyZW5kKGtub3RzID0gdHNpYmJsZTo6eWVhcm1vbnRoKCIyMDE1LTAxIikpICsgc2Vhc29uKCkpDQogIH0gZWxzZSBpZiAoYnJhbmQgPT0gIkJyYW5kIEdyb3VwIDQxIikgew0KICAgIG1kbCAgPC0gVFNMTShzYWxlc18yIH4gdHJlbmQoa25vdHMgPSB0c2liYmxlOjp5ZWFybW9udGgoIjIwMTUtMTEiKSkgKyBzZWFzb24oKSkNCiAgfSBlbHNlIGlmIChicmFuZCA9PSAiQnJhbmQgR3JvdXAgNTEsIDczLCA5MCIpIHsNCiAgICBtZGwgIDwtIFRTTE0oc2FsZXNfMiB+IHRyZW5kKGtub3RzID0gdHNpYmJsZTo6eWVhcm1vbnRoKCIyMDE1LTA3IikpICsgc2Vhc29uKCkpDQogIH0gZWxzZSBpZiAoYnJhbmQgPT0gIkJyYW5kIEdyb3VwIDk2LCA5NyIpIHsNCiAgICBtZGwgIDwtIFRTTE0oc2FsZXNfMiB+IHRyZW5kKGtub3RzID0gdHNpYmJsZTo6eWVhcm1vbnRoKCIyMDE3LTAxIikpICsgc2Vhc29uKCkpDQogIH0gZWxzZSBpZiAoYnJhbmQgPT0gIk90aGVycyIpIHsNCiAgICBtZGwgIDwtIFRTTE0oc2FsZXNfMiB+IHRyZW5kKGtub3RzID0gdHNpYmJsZTo6eWVhcm1vbnRoKCIyMDE2LTAxIikpICsgc2Vhc29uKCkpDQogIH0NCiAgDQogICMgUHJlcGFyZSBhIGxpc3Qgb2YgbW9kZWxzDQogIG1kbF9saXN0IDwtIGxpc3QoDQogICAgbG0gPSBUU0xNKHNhbGVzXzIgfiB0cmVuZCgpICsgc2Vhc29uKCkpLA0KICAgIHN0ZXB3aXNlID0gbWRsDQogICkNCiAgDQogICMgUmV0dXJuIGxpc3QNCiAgcmV0dXJuKG1kbF9saXN0KQ0KfQ0KYGBgDQoNClRoZSBtb2RlbHMgYXJlIGRlZmluZWQgbWFudWFsbHkgZm9yIGVhY2ggYnJhbmQuDQoNCmBgYHtyIHBpZWNld2lzZS1tb2RlbC1kZWZpbml0aW9uLWV4YW1wbGUsIGVjaG89VFJVRSwgZXZhbD1GQUxTRX0NCmdldF9tb2RlbHNfIDwtIGZ1bmN0aW9uKGJyYW5kKSB7DQogICMgRGVmaW5lIHN0ZXAtd2lzZSBtb2RlbHMNCiAgbWRsIDwtIG51bGxfbW9kZWwoKQ0KICBpZiAoYnJhbmQgPT0gIkJyYW5kIEdyb3VwIDE3Iikgew0KICAgIG1kbCAgPC0gVFNMTShzYWxlc18yIH4gdHJlbmQoa25vdHMgPSB0c2liYmxlOjp5ZWFybW9udGgoIjIwMTUtMDMiKSkgKyBzZWFzb24oKSkNCiAgfSBlbHNlIGlmIChicmFuZCA9PSAiQnJhbmQgR3JvdXAgMjQiKSB7DQogICAgLi4uDQogIH0NCn0NCmBgYA0KDQpJbiBicmFuZHMgc3VjaCBhcyAqQnJhbmQgR3JvdXAgMTcqIG9yICpCcmFuZCBHcm91cCAyNCogdGhlIGVmZmVjdCBpcyByZW1hcmthYmxlLiBJdCBpcw0KYWxzbyBpbiBvdGhlcnMsIHN1Y2ggYXMgdGhlICpCcmFuZCBHcm91cCAzMSogYXMgd2UgaGF2ZSBqdXN0IHNlZW4gaW4gdGhlIHByZXZpb3VzIHBsb3RzLg0KDQpgYGB7ciBmaXQtc3RlcHdpc2UtYnktYnJhbmR9DQojIEZpdCBtb2RlbHMgZm9yIGFsbCBicmFuZA0KYnJhbmRzIDwtIHVuaXF1ZSh0cmFpbl9kYXRhJGJyYW5kKSAjIGFsbF9sZXZlbHNfdGJsDQpmaXRfc3RlcHdpc2VfYnJhbmRzIDwtIG1hcF9kZigNCiAgLnggPSBicmFuZHMsIA0KICAuZiA9IH4gYnlfYnJhbmRfdHNpYmJsZSAlPiUgDQogICAgZmlsdGVyKGJyYW5kID09IC54KSAlPiUgDQogICAgbW9kZWwoISEhZ2V0X21vZGVscygueCkgKQ0KKQ0KYGBgDQoNCmBgYHtyIHZpei1zdGVwd2lzZS1icmFuZHMsIGZpZy5oZWlnaHQ9NywgZmlnLndpZHRoPTl9DQpwMSA8LSBmaXRfc3RlcHdpc2VfYnJhbmRzICU+JSANCiAgZmlsdGVyKGJyYW5kICVpbiUgYygiQnJhbmQgR3JvdXAgMTciLCAiQnJhbmQgR3JvdXAgMjQiKSkgJT4lIA0KICBzZWxlY3QoYnJhbmQsIGxtLCBzdGVwd2lzZSkgJT4lIA0KICBmb3JlY2FzdChuZXdfZGF0YSA9IGJ5X2JyYW5kX3RzaWJibGUpICU+JSANCiAgYXV0b3Bsb3QoYnlfYnJhbmRfdHNpYmJsZSwgbGV2ZWwgPSBOVUxMLCBhbHBoYSA9IDAuOSwgc2l6ZSA9IDEpICsNCiAgc2NhbGVfY29sb3JfYnJld2VyKHBhbGV0dGUgPSAiU2V0MiIsIGRpcmVjdGlvbiA9IC0xKSArDQogIHNjYWxlX3lfY29udGludW91cygNCiAgICBsYWJlbHMgPSBzY2FsZXM6OmxhYmVsX251bWJlcihzdWZmaXggPSAiSyIsIHNjYWxlID0gMWUtMykNCiAgKSArIA0KICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlNldDIiLCBkaXJlY3Rpb24gPSAtMSkgKw0KICBsYWJzKHggPSBOVUxMLCB5ID0gTlVMTCkNCg0KcDIgPC0gZml0X3N0ZXB3aXNlX2JyYW5kcyAlPiUgDQogIGZpbHRlcihicmFuZCAlaW4lIGMoIkJyYW5kIEdyb3VwIDMwIiwgIkJyYW5kIEdyb3VwIDMxIikpICU+JSANCiAgc2VsZWN0KGJyYW5kLCBsbSwgc3RlcHdpc2UpICU+JSANCiAgZm9yZWNhc3QobmV3X2RhdGEgPSBieV9icmFuZF90c2liYmxlKSAlPiUgDQogIGF1dG9wbG90KGJ5X2JyYW5kX3RzaWJibGUsIGxldmVsID0gTlVMTCwgYWxwaGEgPSAwLjksIHNpemUgPSAxKSArDQogIHNjYWxlX2NvbG9yX2JyZXdlcihwYWxldHRlID0gIlNldDIiLCBkaXJlY3Rpb24gPSAtMSkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMoDQogICAgbGFiZWxzID0gc2NhbGVzOjpsYWJlbF9udW1iZXIoc3VmZml4ID0gIksiLCBzY2FsZSA9IDFlLTMpDQogICkgKyANCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJTZXQyIiwgZGlyZWN0aW9uID0gLTEpICsNCiAgbGFicyh4ID0gTlVMTCwgeSA9IE5VTEwpDQoNCihwMSB8IHAyKSArIHBsb3RfbGF5b3V0KGd1aWRlcyA9ICJjb2xsZWN0IikNCmBgYA0KDQojIyMgQWxsIHNlcmllcyBhbmFseXNpcw0KDQpOb3cgdGhhdCB3ZSBoYXZlIGlkZW50aWZpZWQgdGhlICprbm90cyogb2YgZWFjaCBicmFuZCBpcyB0aW1lIHRvIGFwcGx5IHRoaXMgbW9kZWxzIGludG8NCnRoZSBwcm9kdWN0IGxldmVsIHNlcmllcy4NCg0KYGBge3IgZml0LXN0ZXB3aXNlLW9uLXNrdS1sZXZlbCwgZWNobz1UUlVFfQ0KZml0X3N0ZXB3aXNlIDwtIG1hcF9kZnIoDQogIC54ID0gc2V0TmFtZXMoYnJhbmRzLCBicmFuZHMpLCANCiAgLmYgPSB+IHRyYWluX2RhdGEgJT4lIA0KICAgIGZpbHRlcihicmFuZCA9PSAueCkgJT4lIA0KICAgIG1vZGVsKCEhIWdldF9tb2RlbHMoLngpWyJzdGVwd2lzZSJdKSwgDQogIC5pZCA9ICJicmFuZCINCikNCmBgYA0KDQpPdmVyYWxsIGFjY3VyYWN5IGlzIG5vdCBhcyBnb29kIGFzIGBjb21ibmAsIGBhcmltYWAgb3JgZXRzYCBtb2RlbHMgdHJhaW5lZCBvbiBbc3RhdGlzdGljYWwNCmJlbmNobWFya3Mgc2VjdGlvbl0oI3N0YXRpc3RpY2FsLWJlbmNobWFya3MpDQoNCmBgYHtyIGZjLWFuZC1hY2Mtc3RlcHdpc2V9DQojIEdlbmVyYXRlIGZvcmVjYXN0cyBmb3IgdGhlIHZhbGlkYXRpb24gcGVyaW9kDQpmY19zdGVwd2lzZSA8LSBmaXRfc3RlcHdpc2UgJT4lIA0KICBmb3JlY2FzdChuZXdfZGF0YSA9IHZhbGlkX2RhdGEpDQoNCiMgQ2FsY3VsYXRlIGFjY3VyYWN5IGZvciBlYWNoIHNlcmllcyBhbmQgbW9kZWwNCmFjY19zdGVwd2lzZSA8LSBmY19zdGVwd2lzZSAlPiUgDQogIGFjY3VyYWN5KGJpbmRfcm93cyh0cmFpbl9kYXRhLCB2YWxpZF9kYXRhKSwgbWVhc3VyZXMpICU+JSANCiAgYWRkX3JhbmsodmFyID0gIk1BUEUiKQ0KDQojIEFnZ3JlZ2F0ZSBtZXRyaWNzIGJ5IGAubW9kZWxgDQphY2Nfc3RlcHdpc2UgJT4lIA0KICBncm91cF9ieSgubW9kZWwpICU+JSANCiAgc3VtbWFyaXNlX2F0KHZhcnMoUk1TU0U6Q1JQUyksIG1lYW4pICU+JSANCiAgYXJyYW5nZShNQVBFKSAlPiUgDQogIHRvX2h0bWwoZGlnaXRzID0gMSkNCmBgYA0KDQpMZXQncyBsb29rIGF0IHNvbWUgb2YgdGhlIHdvcnN0IGZvcmVjYXN0LiBUaGUgYGFyaW1hYCBhbmQgYGV0c2AgbW9kZWxzIHdpbGwgYmUgaW5jbHVkZWQgYXMNCmEgcmVmZXJlbmNlLiBJbiB0aGF0IHdheSwgd2UgY2FuIHVuZGVyc3RhbmQgaG93IHRoZSBgcGllY2V3aXNlYCBtb2RlbCBpcyBtb2RlbGluZyB0aGUNCmRhdGEuIEluIHRoZSBmb2xsb3dpbmcgY2FzZSwgaXQgc2VlbXMgdGhhdCB0aGUgbW9kZWwgaGFzIGZhaWxlZCB0byBjYXB0dXJlIHRoZSB0cmVuZA0KY29ycmVjdGx5IGFuZCBpcyB1bmRlci1mb3JlY2FzdGluZyBtdWNoIG1vcmUgdGhhbiB0aGUgb3RoZXIgdHdvIG1vZGVscy4NCg0KYGBge3IgcGllY2V3aXNlLXdvcnN0LWZvcmVjYXN0cywgZXZhbD1GQUxTRX0NCiMgIyBJbnNwZWNjaW9uYW1vcyBsYXMgcGVvcmVzIHNlcmllcw0KIyBhY2Nfc3RlcHdpc2UgJT4lIA0KIyAgIGFycmFuZ2UoZGVzYyhNQVBFKSkgJT4lIA0KIyAgIGhlYWQoKQ0KYGBgDQoNCmBgYHtyIHZpei1waWVjZXdpc2Utd29yc3QtZm9yZWNhc3RzfQ0KZmNfc3RlcHdpc2UgJT4lDQogIGJpbmRfcm93cyhmY19zdGF0aXN0aWNhbCkgJT4lIA0KICBmaWx0ZXIoDQogICAgaWQgJWluJSBjKCJDbHVzdGVyIDlfX0JyYW5kIEdyb3VwIDMwIiksIA0KICAgIC5tb2RlbCAlaW4lIGMoImFyaW1hIiwgImV0cyIsICJzdGVwd2lzZSIpDQogICkgJT4lIA0KICBhdXRvcGxvdChiaW5kX3Jvd3ModHJhaW5fZGF0YSwgdmFsaWRfZGF0YSksIGxldmVsID0gTlVMTCwgYWxwaGEgPSAwLjkpICsNCiAgZmFjZXRfd3JhcCh2YXJzKGlkKSkgKw0KICBsYWJzKHggPSBOVUxMLCB5ID0gTlVMTCkNCmBgYA0KDQpXaGF0IHdlIGNhbiBkbyBub3c/IExldCdzIHBsb3QgdGhlIHRyZW5kIHRvIHVuZGVyc3RhbmQgd2h5IHRoaXMgaXMgaGFwcGVuaW5nLiBUaGUgbW9kZWwNCmZpdHMgdmVyeSB3ZWxsIHRoZSB0cmVuZCB1cCB0byAyMDE2IGJ1dCwgYWZ0ZXIgdGhhdCBwZXJpb2QsIHRoZSB0cmVuZCBpcyBzdGlsbCBpbiBhDQpkb3dudHJlbmQgYW5kIGl0IHNob3VsZCByZW1haW4gYWxtb3N0IGZsYXQuIFRoZSB2ZXJ0aWNhbCBkYXNoZWQgbGluZXMgaW5kaWNhdGUgdGhlICprbm90cyoNCmRlZmluZWQgd2l0aGluIHRoZSBtb2RlbC4NCg0KYGBge3J9DQojIEZpdCB0cmVuZCBtb2RlbCBiZWNhdXNlIHdlIHdhbnQgdG8gc2VlIGhvdyBpcyB0cmVuZCBjYXB0dXJlZA0KZml0X3RyZW5kXzMwIDwtIHRyYWluX2RhdGEgJT4lIA0KICBmaWx0ZXIoaWQgJWluJSBjKCJDbHVzdGVyIDlfX0JyYW5kIEdyb3VwIDMwIikpICU+JSANCiAgbW9kZWwoDQogICAgcGllY2V3aXNlID0gVFNMTShzYWxlc18yIH4gdHJlbmQoDQogICAgICBrbm90cyA9IGModHNpYmJsZTo6eWVhcm1vbnRoKCIyMDEzLTA3IiksIA0KICAgICAgICAgICAgICAgIHRzaWJibGU6OnllYXJtb250aCgiMjAxNi0wMSIpKSkpDQogICkNCg0KIyBGb3JlY2FzdCB0cmVuZCBtb2RlbA0KZmNfdHJlbmRfMzAgPC0gZml0X3RyZW5kXzMwICU+JSANCiAgZm9yZWNhc3QoaCA9IDEyKQ0KDQojIERpc3BsYXkgcmVhbCB2cyBmaXR0ZWQgZGF0YSBhbmQgZm9yZWNhc3RlZCB0cmVuZA0KZml0X3RyZW5kXzMwICU+JSANCiAgYXVnbWVudCgpICU+JSANCiAgZ2dwbG90KGFlcyh4ID0gZGF0ZSkpICsNCiAgZ2VvbV9saW5lKGFlcyh5ID0gc2FsZXNfMiksIGNvbG91ciA9ICJibGFjayIsIHNlcmllcyA9ICJEYXRhIikgKw0KICBnZW9tX2xpbmUoYWVzKHkgPSAuZml0dGVkKSwgY29sb3VyID0gInN0ZWVsYmx1ZSIsIHNlcmllcyA9ICIuZml0dGVkIikgKw0KICBhdXRvbGF5ZXIoZmNfdHJlbmRfMzAsIGNvbG91ciA9ICJzdGVlbGJsdWUiLCBhbHBoYSA9IDAuMywgbGV2ZWwgPSA5MCkgKw0KICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBjKGFzLkRhdGUoIjIwMTMtMDctMDEiKSwgYXMuRGF0ZSgiMjAxNi0wMS0wMSIpKSwgDQogICAgICAgICAgICAgbGluZXR5cGUgPSAyLCBzaXplID0gMSwgY29sb3IgPSAiZ3JleSIsIGFscGhhID0gMC40KSArDQogIGxhYnMoDQogICAgeCA9IE5VTEwsDQogICAgeSA9ICJEYXRhIHZzIEZpdHRlZCAocHJlZGljdGVkIHZhbHVlcykiLA0KICAgIHRpdGxlID0gIlRyZW5kIGNhcHR1cmVkIGJ5IHRoZSBwaWVjZXdpc2UgbW9kZWwiLCANCiAgICBzdWJ0aXRsZSA9ICJDbHVzdGVyIDlfX0JyYW5kIEdyb3VwIDMwIg0KICApDQpgYGANCg0KRmluYWxseSwgd2Ugc2hvdyB0aGUgZm9yZWNhc3QgZm9yIHRoZSBzZXJpZXMgdGhhdCB3ZSBoYXZlIGJlZW4gbG9va2luZyBpbiB0aGUgcHJldmlvdXMNCnNlY3Rpb25zLg0KDQpgYGB7ciB2aXotc3RlcHdpc2UtMDJ9DQpmaXRfc3RlcHdpc2UgJT4lDQogIGZpbHRlcihpZCA9PSAiQ2x1c3RlciA3X19CcmFuZCBHcm91cCAzMCIpICU+JQ0KICBsZWZ0X2pvaW4oc2VsZWN0KGZpdF9zdGF0aXN0aWNhbCwgaWQsIGV0cywgYXJpbWEpLCBieSA9ICJpZCIpICU+JSANCiAgZm9yZWNhc3QobmV3X2RhdGEgPSB2YWxpZF9kYXRhKSAlPiUgDQogIHBsb3RfZm9yZWNhc3QoZmFjZXRzID0gIi5tb2RlbCIsIG5jb2wgPSBOVUxMLCBsZXZlbCA9IE5VTEwsIHRpdGxlID0gIiIpICsNCiAgZmFjZXRfd3JhcCh+IGlkKQ0KYGBgDQoNCmBgYHtyIHZpei1zdGVwd2lzZS0wMSwgZWNobz1UUlVFfQ0KZml0X3N0ZXB3aXNlICU+JSANCiAgZmlsdGVyKGlkID09ICJDbHVzdGVyIDJfX090aGVycyIpICU+JQ0KICBsZWZ0X2pvaW4oc2VsZWN0KGZpdF9zdGF0aXN0aWNhbCwgaWQsIGV0cywgYXJpbWEpLCBieSA9ICJpZCIpICU+JSANCiAgZm9yZWNhc3QobmV3X2RhdGEgPSB2YWxpZF9kYXRhKSAlPiUgDQogIHBsb3RfZm9yZWNhc3QoZmFjZXRzID0gIi5tb2RlbCIsIG5jb2wgPSBOVUxMLCBsZXZlbCA9IE5VTEwsIHRpdGxlID0gIiIpICsNCiAgZmFjZXRfd3JhcCh+IGlkKQ0KYGBgDQoNCiMjIFNlbGVjdGluZyBiZXN0IG1vZGVsDQoNClRocm91Z2hvdXQgdGhlIG5vdGVib29rIHdlIGhhdmUgc2VlbiBob3cgZWFjaCBtb2RlbCBpcyBiZXR0ZXIgc3VpdGVkIHRvIG9uZSBzcGVjaWZpYyBjYXNlLA0KaW4gc29tZSBjYXNlcyBhIG1vZGVsIGFzIHNpbXBsZSBhcyB0aGUgYG5haXZlYCBnaXZlIHVzIHRoZSBiZXN0IHJlc3VsdHMsIGhvd2V2ZXIsIGluIG90aGVyDQpjYXNlcyB3ZSBuZWVkIG1vcmUgY29tcGxleCBtb2RlbHMgdG8gY2FwdHVyZSB0aGUgc2lnbmFsIG9mIHRoZSBzZXJpZXMuIFNvLCB3aHkgbm90IHNlbGVjdA0KdGhlIGJlc3QgbW9kZWwgZm9yIGVhY2ggc2VyaWVzIGluc3RlYWQgb2YgYWx3YXlzIHVzaW5nIHRoZSBzYW1lIG1vZGVsIGZvciBldmVyeXRoaW5nPw0KDQpgYGB7ciBhY2N1cmFjeS1hbGwtbW9kZWxzLCBlY2hvPVRSVUV9DQojIENvbWJpbmUgYWxsIGFjY3VyYWNpZXMgdG9nZXRoZXINCmFjY19hbGwgPC0gDQogIGJpbmRfcm93cyhhY2NfYmFzZWxpbmVzLCBhY2Nfc3RhdGlzdGljYWwsIGFjY194cmVnLCBhY2Nfc3RlcHdpc2UpICU+JSANCiAgYWRkX3JhbmsodmFyID0gIk1BUEUiKQ0KDQojIFNlbGVjdCBiZXN0IG1vZGVsIGZvciBlYWNoIHNlcmllDQphY2NfYmVzdF9tb2RlbHMgPC0gYWNjX2FsbCAlPiUgDQogIGFycmFuZ2UoaWQsIHJhbmspICU+JSANCiAgdG9wX24oLXJhbmssIG4gPSAxKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShpZCkgJT4lIA0KICBkcGx5cjo6c2xpY2UoMSkgJT4lIA0KICB1bmdyb3VwKCkNCmBgYA0KDQpUaGUgZXJyb3IgaGFzIGJlZW4gcmVkdWNlZCBieSBhbiA0NyUgd2l0aCByZXNwZWN0IHRvIHRoZSBgbmFpdmVgIGFuZCAyOCUgd2l0aCByZXNwZWN0IHRvDQp0aGUgYGNvbWJuYCBtb2RlbC4NCg0KYGBge3IgZXZhbD1GQUxTRX0NCiMgbm4gPC0gMjYuOSAgICAjIG5haXZlIG1vZGVsDQojIGNjIDwtIDE0LjEgICAgIyBiZXN0IG1vZGVsIGZvciBlYWNoIHNlcmllDQojIChjYyAvIG5uKSAtIDEgIyByZWR1Y3Rpb24gcGVyY2VudGFnZQ0KIyAjIFsxXSAwLjQ3NTgzNjQNCiMgDQojIG5uIDwtIDE5LjggICAgIyBjb21ibiBtb2RlbA0KIyBjYyA8LSAxNC4xICAgICMgYmVzdCBtb2RlbCBmb3IgZWFjaCBzZXJpZQ0KIyAoY2MgLyBubikgLSAxICMgcmVkdWN0aW9uIHBlcmNlbnRhZ2UNCiMgIyAtMC4yODc4Nzg4DQpgYGANCg0KYGBge3IgYWNjdXJhY3ktc3VtbWFyeS1iZXN0LW1vZGVsLCBlY2hvPVRSVUV9DQphY2NfYmVzdF9tb2RlbHMgJT4lIA0KICBzdW1tYXJpc2VfYXQodmFycyhSTVNTRTpDUlBTKSwgbWVhbikgJT4lIA0KICBhZGRfY29sdW1uKC5tb2RlbCA9ICJCZXN0IG1vZGVsIiwgLmJlZm9yZSA9IDEpICU+JSANCiAgYXJyYW5nZShNQVBFKSAlPiUgDQogIHRvX2h0bWwoZGlnaXRzID0gMSkNCmBgYA0KDQpgYGB7ciBzYWZldHktY2hlY2stbW9kZWwtdGllc30NCiMgIyBTYWZldHkgY2hlY2s6IGRvIG5vdCBleGlzdCBkdXBsaWNhdGVzIGluIGNhc2Ugb2YgdGllcy4NCiMgYmVzdF9tb2RlbHMgJT4lIA0KIyAgIGNvdW50KGlkLCBzb3J0ID0gVCkNCmBgYA0KDQpIb3cgbWFueSB0aW1lcyBlYWNoIG1vZGVsIGhhcyBiZWVuIHNlbGVjdGVkPyBgc3RlcHdpc2VgIGFuZCBgYXJpbWFgIGFyZSB0aGUgdHdvIGJlc3QgbW9kZWxzDQpmb2xsb3dlZCBieSBgeHJlZ180YC4gUmVjYWxsIHRoYXQgdGhpcyBtb2RlbCB1c2VzIGFsbCB0aGUgaW52ZXN0bWVudHMgcHJvdmlkZWQuDQoNCmBgYHtyIHRpbWUtZWFjaC1tb2RlbC1zZWxlY3RlZCwgZmlnLmhlaWdodD01fQ0KYWNjX2Jlc3RfbW9kZWxzICU+JSANCiAgY291bnQoLm1vZGVsLCBzb3J0ID0gVFJVRSkgJT4lIA0KICBnZ3Bsb3QoYWVzKHggPSBmY3RfcmVvcmRlcigubW9kZWwsIG4pLCB5ID0gbikpICsNCiAgZ2VvbV9jb2woZmlsbCA9ICIjNzI5RUNFIiwgYWxwaGEgPSAwLjkpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKG4uYnJlYWtzID0gMTApICsNCiAgbGFicygNCiAgICB0aXRsZSA9ICJIb3cgbWFueSB0aW1lcyBlYWNoIG1vZGVsIGhhcyBiZWVuIHNlbGVjdGVkPyIsIA0KICAgIHggPSAiIiwgeSA9ICJDb3VudCINCiAgKSArDQogIGNvb3JkX2ZsaXAoKSArDQogIHRoZW1lKA0KICAgIHBhbmVsLmdyaWQubWFqb3IueSA9IGVsZW1lbnRfYmxhbmsoKSwgDQogICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKQ0KICApDQpgYGANCg0KSW4gdGhlIHNhbWUgd2F5IHRoYXQgd2UgaGF2ZSBiZWVuIGRvaW5nLCB3ZSBhcmUgZ29pbmcgdG8gc2hvdyB0aGUgYmVzdCBhbmQgd29yc3QNCnByZWRpY3Rpb25zIHRvIGdldCBhbiBpZGVhIG9mIHdoYXQgdGhlIHByZWRpY3Rpb25zIGFyZSBsaWtlLg0KDQpgYGB7ciBmb3JlY2FzdC1hbGwtbW9kZWxzLCBlY2hvPVRSVUV9DQojIENvbWJpbmUgYWxsIGZvcmVjYXN0cw0KZmNfYWxsX21vZGVscyA8LSBiaW5kX3Jvd3MoZmNfYmFzZWxpbmVzLCBmY19zdGF0aXN0aWNhbCwgZmNfeHJlZywgZmNfc3RlcHdpc2UpDQoNCmZjX2Jlc3RfbW9kZWxzIDwtIGZjX2FsbF9tb2RlbHMgJT4lIA0KICBzZW1pX2pvaW4oYWNjX2Jlc3RfbW9kZWxzLCBieSA9IGMoIi5tb2RlbCIsICJpZCIpKQ0KYGBgDQoNCmBgYHtyIGJlc3QtbW9kZWxzLWJlc3QtZm9yZWNhc3RzLCBmaWcuaGVpZ2h0PTcsIGZpZy53aWR0aD05fQ0KdG9wX25fZm9yZWNhc3RzIDwtIGFjY19iZXN0X21vZGVscyAlPiUgDQogIGFycmFuZ2UoTUFQRSkgJT4lIA0KICBoZWFkKDQpDQoNCmZjX2Jlc3RfbW9kZWxzICU+JSANCiAgZmlsdGVyKGlkICVpbiUgdG9wX25fZm9yZWNhc3RzJGlkKSAlPiUgDQogIHBsb3RfZm9yZWNhc3QoZmFjZXRzID0gImlkIiwgbGV2ZWwgPSBOVUxMLCBuY29sID0gMiwgc2NhbGVzID0gImZyZWVfeSIsIA0KICAgICAgICAgICAgICAgIHRpdGxlID0gIkJlc3QgcGVyZm9ybWluZyBmb3JlY2FzdCIpDQogICMgbGFicyh0aXRsZSA9ICJCZXN0IHBlcmZvcm1pbmcgZm9yZWNhc3QiKQ0KYGBgDQoNClNvbWV0aW1lcywgYW55IG1vZGVsIGlzIGFibGUgdG8gcHJlZGljdCB0aGUgZGF0YSBhY2N1cmF0ZWx5LiBNaWdodCBiZSwgYmVjYXVzZSB0aGUgc2VyaWVzDQphcmUgd2hpdGUgbm9pc2Ugb3IgdGhlIHNpZ25hbC10by1ub2lzZSByYXRpbyBpcyB2ZXJ5IGxvdy4gT3RoZXIgdGltZXMsIHRoZXJlIGFyZSB2ZXJ5DQphYnJ1cHQgY2hhbmdlcyB0aGF0IGNhbm5vdCBiZSBleHBsYWluZWQgYnkgYW55IHByZWRpY3RvciAocGFzdCBzYWxlcywgaW52ZXN0bWVudHMsIGV0Yy4pDQoNCmBgYHtyIGJlc3QtbW9kZWxzLXdvcnN0LWZvcmVjYXN0cywgZmlnLmhlaWdodD03LCBmaWcud2lkdGg9OX0NCndvcnN0XzRfZm9yZWNhc3RzIDwtIGFjY19iZXN0X21vZGVscyAlPiUgDQogIGFycmFuZ2UoTUFQRSkgJT4lIA0KICB0YWlsKDQpDQoNCmZjX2Jlc3RfbW9kZWxzICU+JSANCiAgZmlsdGVyKGlkICVpbiUgd29yc3RfNF9mb3JlY2FzdHMkaWQpICU+JSANCiAgcGxvdF9mb3JlY2FzdChmYWNldHMgPSAiaWQiLCBsZXZlbCA9IE5VTEwsIG5jb2wgPSAyLCBzY2FsZXMgPSAiZnJlZV95IiwgDQogICAgICAgICAgICAgICAgdGl0bGUgPSAiV29yc3QgcGVyZm9ybWluZyBmb3JlY2FzdCIpDQogICMgbGFicyh0aXRsZSA9ICJXb3JzdCBwZXJmb3JtaW5nIGZvcmVjYXN0IikNCmBgYA0KDQojIyMgRHJpbGwgZG93biBhY2N1cmFjeQ0KDQpGb3JlY2FzdHMgYXJlIG9mdGVuIHJlcXVpcmVkIGZvciBhbGwgbGV2ZWxzIG9mIHRoZSBzZXJpZXMsIGFuZCBpdCBpcyBuYXR1cmFsIHRoYXQgdGhlDQpmb3JlY2FzdHMgdG8gYWRkIHVwIGluIHRoZSBzYW1lIHdheSBhcyB0aGUgZGF0YS4gVGhpcyBpcyBpbXBvcnRhbnQgYmVjYXVzZSB0aGUgZm9yZWNhc3QNCndpbGwgYmUgYW5hbHl6ZWQgZnJvbSBkaWZmZXJlbnQgcG9pbnRzIG9mIHZpZXcgYW5kIGFsbCBvZiB0aGVtIG11c3QgYmUgYWxpZ25lZC4gRm9yDQpleGFtcGxlLCBhIGJyYW5kIG1hbmFnZXIgbWlnaHQgYmUgaW50ZXJlc3RlZCBpbiB0aGUgZm9yZWNhc3Qgb2YgYWxsIG9mIHRoZWlyIHByb2R1Y3RzIGJ1dA0KaXQgYWxzbyB3b3VsZCBtaWdodCBnZXQgYSB2aWV3IGF0IGNvdW50cnkgbGV2ZWwgb2YgdGhlaXIgYnJhbmQuIEF0IHRoZSBzYW1lIHRpbWUsIHRoZSBDRU8NCm9mIHRoZSBjb21wYW55LCBtaWdodCBiZSBpbnRlcmVzdGVkIGluIGhpZ2hlciBsZXZlbHMgb2YgYWdncmVnYXRpb24uDQoNClRoZSBlYXNpZXN0IGJyYW5kIHRvIGZvcmVjYXN0IGlzICpCcmFuZCBHcm91cCA5NiwgOTcqIGFuZCB0aGUgaGFyZGVzdCBpcyAqQnJhbmQgR3JvdXAgMjQqDQp3aGljaCBpcyBub3QgYSBzdXJwcmlzZSBnaXZlbiBpdCdzIGhpZ2hlc3QgZ3Jvd3RoLg0KDQpgYGB7ciBhY2N1cmFjeS1zdW1tYXJ5LWJlc3QtbW9kZWwtYnJhbmQtbGV2ZWx9DQphY2NfYmVzdF9tb2RlbHMgJT4lIA0KICBzZXBhcmF0ZShjb2wgPSAiaWQiLCBpbnRvID0gYygiY2x1c3RlciIsICJicmFuZCIpLCBzZXAgPSAiX18iKSAlPiUgDQogIGdyb3VwX2J5KGJyYW5kKSAlPiUgDQogIHN1bW1hcmlzZV9hdCh2YXJzKFJNU1NFOkNSUFMpLCBtZWRpYW4pICU+JSANCiAgYWRkX2NvbHVtbigubW9kZWwgPSAiQmVzdCBtb2RlbCIsIC5iZWZvcmUgPSAxKSAlPiUgDQogIGFycmFuZ2UoTUFQRSkgJT4lIA0KICB0b19odG1sKGRpZ2l0cyA9IDEsIGZ1bGxfd2lkdGggPSBGQUxTRSkNCmBgYA0KDQpJbiB0aGUgc2FtZSB3YXksIHRoZSBlYXNpZXN0IGNsdXN0ZXIgaXMgKkNsdXN0ZXIgOCogYW5kIHRoZSBoYXJkZXN0IGlzICpDbHVzdGVyIDcqDQoNCmBgYHtyIGFjY3VyYWN5LXN1bW1hcnktYmVzdC1tb2RlbC1jbHVzdGVyLWxldmVsfQ0KYWNjX2Jlc3RfbW9kZWxzICU+JSANCiAgc2VwYXJhdGUoY29sID0gImlkIiwgaW50byA9IGMoImNsdXN0ZXIiLCAiYnJhbmQiKSwgc2VwID0gIl9fIikgJT4lIA0KICBncm91cF9ieShjbHVzdGVyKSAlPiUgDQogIHN1bW1hcmlzZV9hdCh2YXJzKFJNU1NFOkNSUFMpLCBtZWRpYW4pICU+JSANCiAgYWRkX2NvbHVtbigubW9kZWwgPSAiQmVzdCBtb2RlbCIsIC5iZWZvcmUgPSAxKSAlPiUgDQogIGFycmFuZ2UoTUFQRSkgJT4lIA0KICB0b19odG1sKGRpZ2l0cyA9IDEsIGZ1bGxfd2lkdGggPSBGQUxTRSkNCmBgYA0KDQojIyBNYWtlIGZvcmVjYXN0cw0KDQpUaGUgbGFzdCBzdGVwIGlzIGdlbmVyYXRlIHRoZSBmb3JlY2FzdCBmb3IgYWxsIHRoZSA3NSBzZXJpZXMuIE5vdywgd2UgbXVzdCBlc3RpbWF0ZSB0aGUNCm1vZGVscyBhZ2FpbiBidXQgdXNpbmcgYWxsIHRoZSBkYXRhIGF2YWlsYWJsZS4NCg0KYGBge3Igc3RhcnQtcGFyYWxsZWxpemF0aW9uLWFnYWlufQ0KIyAjIFN0YXJ0IHBhcmFsbGVsaXphdGlvbiBhZ2Fpbg0KIyBteV9wbGFuIDwtIGZ1dHVyZTo6cGxhbigibXVsdGlzZXNzaW9uIiwgd29ya2VycyA9IDJMKQ0KYGBgDQoNCmBgYHtyIHJlZml0LW1vZGVscywgZWNobz1UUlVFLCBldmFsPUZBTFNFfQ0KIyBDb21iaW5lIGFsbCB0aHJlZSBsaXN0IG9mIG1vZGVscw0KbW9kZWxzX2xpc3QgPC0gYyhtb2RlbHMsIG1vZGVsc19zdGF0LCBtb2RlbHNfeHJlZykNCg0KIyBGaXQgbW9kZWxzIHVzaW5nIGFsbCB0cmFpbiBkYXRhDQpmaXRfYWxsX21vZGVsc18xIDwtIHRyYWluX2RhdGEgJT4lDQogIGJpbmRfcm93cyh2YWxpZF9kYXRhKSAlPiUNCiAgbW9kZWwoISEhbW9kZWxzX2xpc3QpICU+JQ0KICBtdXRhdGUoY29tYm4gPSAoYXJpbWEgKyBldHMpIC8gMikNCg0KIyBUcmFpbiBwaWVjZS13aXNlIG1vZGVscw0KZml0X2FsbF9tb2RlbHNfMiA8LSBtYXBfZGZyKA0KICAueCA9IHNldE5hbWVzKGJyYW5kcywgYnJhbmRzKSwNCiAgLmYgPSB+IHRyYWluX2RhdGEgJT4lDQogICAgYmluZF9yb3dzKHZhbGlkX2RhdGEpICU+JQ0KICAgIGZpbHRlcihicmFuZCA9PSAueCkgJT4lDQogICAgbW9kZWwoISEhZ2V0X21vZGVscygueClbInN0ZXB3aXNlIl0pLA0KICAuaWQgPSAiYnJhbmQiDQopDQoNCiMgQ29tYmluZSBhbGwgbW9kZWxzIHRvZ2V0aGVyDQpmaXRfYWxsX21vZGVscyA8LSBmaXRfYWxsX21vZGVsc18xICU+JSANCiAgbGVmdF9qb2luKGZpdF9hbGxfbW9kZWxzXzIsIGJ5ID0gImlkIikNCg0KIyBTYXZlIG1vZGVscw0Kd3JpdGVfcmRzKGZpdF9hbGxfbW9kZWxzLCANCiAgZmlsZS5wYXRoKHBhdGhfbW9kZWxzLCAiZml0X2FsbF9tb2RlbHMucmRzIiksIA0KICBjb21wcmVzcyA9ICJneiIpDQpgYGANCg0KYGBge3IgbG9hZC1tb2RlbHN9DQojIExvYWQgYWxsIG1vZGVscw0KZml0X2FsbF9tb2RlbHMgPC0gcmVhZF9yZHMoZmlsZS5wYXRoKHBhdGhfbW9kZWxzLCAiZml0X2FsbF9tb2RlbHMucmRzIikpDQoNCmdldF9iZXN0X21vZGVsX2NvbHVtbiA8LSBmdW5jdGlvbihkYXRhLCAuLi4pIHsNCiAgdHJhbnNtdXRlKGRhdGEsIC4uLiwgYmVzdF9tb2RlbCA9IGdldChkYXRhJC5tb2RlbCkpDQp9DQoNCiMgS2VlcCBvbmx5IHRoZSBiZXN0IG1vZGVsIGZvciBlYWNoIGBpZGANCmZpdF9iZXN0X21vZGVscyA8LSBmaXRfYWxsX21vZGVscyAlPiUgDQogIGxlZnRfam9pbihzZWxlY3QoYWNjX2Jlc3RfbW9kZWxzLCBpZCwgLm1vZGVsKSwgYnkgPSAiaWQiKSAlPiUgDQogIHNwbGl0KC4kaWQpICU+JQ0KICBtYXBfZGYoZ2V0X2Jlc3RfbW9kZWxfY29sdW1uLCBpZCwgLm1vZGVsKSAlPiUNCiAgYXNfbWFibGUoa2V5ID0gImlkIiwgbW9kZWwgPSAiYmVzdF9tb2RlbCIpDQpgYGANCg0KYGBge3IgZ2VuZXJhdGUtZm9yZWNhc3RzLWZvci0yMDE4fQ0KIyBHZW5lcmF0ZSBmb3JlY2FzdHMgZm9yIHRoZSBmdXR1cmUgKDIwMTgpDQpmY19mdXR1cmUgPC0gZml0X2Jlc3RfbW9kZWxzICU+JSANCiAgc2VsZWN0KC0ubW9kZWwpICU+JSANCiAgZm9yZWNhc3QobmV3X2RhdGEgPSB0ZXN0X2RhdGEpDQpgYGANCg0KYGBge3Igdml6LWZpbmFsLWZvcmVjYXN0fQ0KdGhpc19pZCA8LSAiQ2x1c3RlciAxX19CcmFuZCBHcm91cCAzMSINCmZjX2Z1dHVyZSAlPiUgDQogIGZpbHRlcihpZCA9PSB0aGlzX2lkKSAlPiUgDQogIGF1dG9wbG90KGJpbmRfcm93cyh0cmFpbl9kYXRhLCB2YWxpZF9kYXRhKSwgbGV2ZWwgPSA5MCkgKw0KICBmYWNldF93cmFwKH5pZCkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsNCiAgbGFicyh4ID0gTlVMTCwgeSA9IE5VTEwpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKA0KICAgIGxhYmVscyA9IHNjYWxlczo6bGFiZWxfbnVtYmVyKHN1ZmZpeCA9ICJLIiwgc2NhbGUgPSAxZS0zKQ0KICApDQpgYGANCg0KIyBSZXNvdXJjZSBBbGxvY2F0aW9uDQoNClJlc291cmNlIGFsbG9jYXRpb24gbWV0aG9kcyBjYW4gYmUgdXNlZCBpbiBhbG1vc3QgZXZlcnkgYXNwZWN0IG9mIHN1cHBseSBjaGFpbiBtYW5hZ2VtZW50Lg0KVGhlIGNvbW1vbiBnb2FsIGlzIGFsbG9jYXRlIHRoZSByZXNvdXJjZXMgZWZmZWN0aXZlbHkgKGkuZS4sIG1heGltaXppbmcgdGhlIHJldmVudWUsDQptaW5pbWl6aW5nIHRoZSBjb3N0LCBvciBvcHRpbWl6aW5nIHRoZSB1dGlsaXphdGlvbiBzZXF1ZW5jZSkgd2hpbGUgc2F0aXNmeWluZyBjZXJ0YWluDQpjb25zdHJhaW50cyAoZS5nLiwgcmVzb3VyY2UgYXZhaWxhYmlsaXR5LCBjdXN0b21lciBzZXJ2aWNlIGxldmVsLCBiYWNrIG9yZGVyIGxldmVsLA0KZGVsaXZlcnkgd2luZG93KS4gSW4gdGhpcyBjYXNlLCByZXNvdXJjZXMgcmVmZXJzIHRvIGludmVzdG1lbnRzLg0KDQpJbiB0aGlzIHNlY29uZCBwYXJ0IG9mIHRoZSBjaGFsbGVuZ2UsIE5vdmFydGlzIGFzayB0byB0aGUgcGFydGljaXBhbnRzIHRvIHByb3ZpZGUgdGhlDQpvcHRpbWFsIGFsbG9jYXRpb24gb2YgdGhlaXIgcmVzb3VyY2VzIGZvciB0aGUgeWVhciAyMDE4LCBhcyB3ZWxsIGFzLCBzaG93aW5nIGRpZmZlcmVuY2VzDQpvZiBhbGxvY2F0aW9ucyBieSBjbHVzdGVyL2JyYW5kL2ludmVzdG1lbnQgdHlwZSBhbmQgaW1wYWN0IG9uIHNhbGVzLiBJbnZlc3RtZW50cyBhcmUgbm93DQpjb21wcmVzc2VkIGludG8gKkludmVzdG1lbnQgMSosICpJbnZlc3RtZW50IDIqIGFuZCAqT3RoZXJzKi4NCg0KVGhlIHRlbXBsYXRlIGZpbGUgcHJvdmlkZWQgYnkgdGhlIG9yZ2FuaXphdGlvbiBsb29rcyBhcyBmb2xsb3c6DQoNCmBgYHtyIHJlYWQtdGVtcGxhdGUtZGF0YX0NCnN1Yl90ZW1wbGF0ZV8yIDwtIA0KICByZWFkX2NzdihmaWxlLnBhdGgocGF0aF9kYXRhLCAiU3VibWlzc2lvbl9UZW1wbGF0ZTIuY3N2IikpICU+JQ0KICByZW5hbWUoDQogICAgY2x1c3RlciA9IENsdXN0ZXIsDQogICAgYnJhbmQgPSBgQnJhbmQgR3JvdXBgLCANCiAgICBgZnVuY3Rpb25gID0gRnVuY3Rpb24NCiAgKQ0KDQojIFNob3cgZmlyc3Qgcm93cyBhbmQgY29sdW1ucw0KaGVhZChzdWJfdGVtcGxhdGVfMiwgMykgJT4lIA0KICB0b19odG1sKGRpZ2l0cyA9IDEpDQpgYGANCg0KQ3JlYXRlIHRoZSBuZXcgdmFyaWFibGUgYGludmVzdG1lbnRfb3RoZXJzYCwgYW5kIHJlbW92ZSB1bm5lY2Vzc2FyeSBjb2x1bW5zLg0KDQpgYGB7ciBjcmVhdGUtaW52ZXN0bWVudC1vdGhlcnMsIGVjaG89VFJVRX0NCmFsbG9jX2RmIDwtIGFsbF9sZXZlbHNfdGJsICU+JSANCiAgbXV0YXRlKA0KICAgIGludmVzdG1lbnRfb3RoZXJzID0gaW52ZXN0bWVudF8zICsgaW52ZXN0bWVudF80ICsgDQogICAgICBpbnZlc3RtZW50XzUgKyBpbnZlc3RtZW50XzYNCiAgKSAlPiUgDQogIHNlbGVjdCgtYyhpbnZlc3RtZW50XzMsIGludmVzdG1lbnRfNCwgaW52ZXN0bWVudF81LCBpbnZlc3RtZW50XzYpKQ0KYGBgDQoNCmBgYHtyIHByaW50LWFsbG9jX2RmfQ0KIyBTaG93IGZpcnN0IHJvd3MgYW5kIGNvbHVtbnMNCmhlYWQoYWxsb2NfZGYsIDMpICU+JSANCiAgdG9faHRtbChkaWdpdHMgPSAxKQ0KYGBgDQoNCiMjIEZvcmVjYXN0aW5nIG1vZGVsDQoNCldlIG5lZWQgYSBmb3JlY2FzdGluZyBtb2RlbCB3aXRoIGludmVzdG1lbnRzIGFzIHByZWRpY3RvcnMuIElkZWFsbHksIHRoZSBtb2RlbCBvYnRhaW5lZCBpbg0KdGhlIGZpcnN0IGNoYWxsZW5nZSBpcyB0aGUgb25lIHRoYXQgd2Ugc2hvdWxkIHVzZSB0byBwZXJmb3JtIHRoZSBvcHRpbWl6YXRpb24uIEhvd2V2ZXIsDQpzb21lIG9mIHRoZSBtb2RlbHMgYXJlIHVuaXZhcmlhdGUgYW5kIGluIGFueSBjYXNlIHRoZSB2YXJpYWJsZSBgaW52ZXN0bWVudF9vdGhlcnNgIGhhcw0KYmVlbiB1c2VkLiBUaGVyZWZvcmUsIGEgbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWwgd2lsbCBiZSB1c2VkLCB3aGljaCB3aWxsIHVzZSB0aGUgdHJlbmQsDQp0aGUgc2Vhc29uYWxpdHkgYW5kIHRoZSBpbnZlc3RtZW50cyBhcyBwcmVkaWN0b3JzLg0KDQoqTm90ZTogd2Ugc2hvdWxkIGxvb2sgZm9yIHRoZSBiZXN0IG1vZGVsIHBvc3NpYmxlIHRoYXQgY29udGFpbnMgaW52ZXN0bWVudHMgYXMNCnByZWRpY3RvcnMuKg0KDQpgYGB7ciByZXMtYWxsb2Mtc3BsaXQtZGF0YX0NCnRyYWluX2RhdGFfYWxsb2MgPC0gYWxsb2NfZGYgJT4lIA0KICBmaWx0ZXIoZGF0ZSA8IHllYXJtb250aChmaXJzdF9kYXRlX3N1Ym1pc3Npb24pKQ0KDQp0ZXN0X2RhdGFfYWxsb2MgPC0gYWxsb2NfZGYgJT4lIA0KICBmaWx0ZXIoZGF0ZSA+PSB5ZWFybW9udGgoZmlyc3RfZGF0ZV9zdWJtaXNzaW9uKSkNCmBgYA0KDQpgYGB7ciByZXMtYWxsb2MtbW9kZWwtZGVmaW5pdGlvbiwgZWNobz1UUlVFfQ0KbW9kZWxzX2FsbG9jIDwtIGxpc3QoDQogIGxtID0gVFNMTShzYWxlc18yIH4gdHJlbmQoKSArIHNlYXNvbigpICsgaW52ZXN0bWVudF8xICsgaW52ZXN0bWVudF8yICsNCiAgICAgICAgICAgICAgaW52ZXN0bWVudF9vdGhlcnMpDQopDQpgYGANCg0KVGhlbiwgdHJhaW4gdGhlIG1vZGVscyBhbmQgZ2VuZXJhdGUgdGhlIGZvcmVjYXN0cyBmb3IgdGhlIG5leHQgMTIgbW9udGhzDQoNCmBgYHtyIHJlcy1hbGxvYy1maXQtbW9kZWxzLCBlY2hvPVRSVUV9DQojIFRyYWluIG1vZGVscw0KZml0X2FsbG9jIDwtIHRyYWluX2RhdGFfYWxsb2MgJT4lIA0KICBtb2RlbCghISFtb2RlbHNfYWxsb2MpDQoNCiMgR2VuZXJhdGUgZm9yZWNhc3RzIGZvciB0aGUgdGVzdCBwZXJpb2QNCmZjX2FsbG9jIDwtIGZpdF9hbGxvYyAlPiUgDQogIGZvcmVjYXN0KG5ld19kYXRhID0gdGVzdF9kYXRhX2FsbG9jKQ0KYGBgDQoNCmBgYHtyIHJlcy1hbGxvYy12aXotMX0NCiMgT25jZSB0aGUgbW9kZWxzIGFyZSB0cmFpbmVkLCB3ZSBjYW4gdmlzdWFsaXplIHRoZSBwcmVkaWN0aW9ucyBmb3IgdGhlIG5leHQgMTIgbW9udGhzLg0KIyBmY19hbGxvYyAlPiUgDQojICAgZmlsdGVyKGlkID09ICJDbHVzdGVyIDVfX0JyYW5kIEdyb3VwIDk2LCA5NyIpICU+JSANCiMgICBhdXRvcGxvdCh0cmFpbl9kYXRhX2FsbG9jLCBhbHBoYSA9IDAuNSwgbGV2ZWwgPSBOVUxMLCBzaXplID0gMSkgKw0KIyAgIGZhY2V0X3dyYXAofiBpZCkgKw0KIyAgIGxhYnMoeCA9IE5VTEwsIHkgPSBOVUxMKSArDQojICAgc2NhbGVfeV9jb250aW51b3VzKA0KIyAgICAgbGFiZWxzID0gc2NhbGVzOjpsYWJlbF9udW1iZXIoc3VmZml4ID0gIksiLCBzY2FsZSA9IDFlLTMpDQojICAgKQ0KYGBgDQoNCmBgYHtyIGFnZ3JlZ2F0ZS1mb3JlY2FzdC0yMDE4fQ0KZmNfYWdnXzIwMTggPC0gZmNfYWxsb2MgJT4lIA0KICBhc190aWJibGUoKSAlPiUgDQogIGdyb3VwX2J5KGlkLCAubW9kZWwpICU+JSANCiAgc3VtbWFyaXNlKEZvcmVjYXN0ZWRTYWxlcyA9IHN1bSgubWVhbikpDQpgYGANCg0KIyMgU2ltdWxhdGlvbnMNCg0KV2hlbiBhIGNsb3NlZCBmb3JtIGlzIG5vdCBhdmFpbGFibGUgdG8gZXN0aW1hdGUgdGhlIHZhbHVlIG9mIGEgcGFyYW1ldGVyLCBlaXRoZXIgYmVjYXVzZQ0KaXQgZG9lcyBub3QgaGF2ZSBhIGNsb3NlZCBmb3JtIGZvcm11bGEgb3IgYmVjYXVzZSB0aGVyZSBhcmUgdG9vIG1hbnkgZmFjdG9yIHRoYXQgaW5mbHVlbmNlDQppbiB0aGUgZmluYWwgcmVzdWx0LCB0aGUgdXNlIG9mIHNpbXVsYXRpb24gdGVjaG5pcXVlcyBhcmUgY29tbW9ubHkgdXNlZCB0byBvYnNlcnZlIHRoZQ0KYmVoYXZpb3Igb2YgdGhlIHZhcmlhYmxlIHRvIGJlIGFuYWx5emVkLg0KDQpUaGUgbW9kZWwgd2lsbCBiZSBmZWQgd2l0aCB2YXJpYXRpb25zIG9mIHRoZSBpbnZlc3RtZW50cyB0byBvYnRhaW4gZGlmZmVyZW50IGZvcmVjYXN0cy4NClNvbWV0aW1lcyByZWR1Y2luZyB0aGUgYW1vdW50IGludmVzdGVkIG9uIG9uZSBzaWRlIHRvIHBsYWNlIGl0IGluIGFub3RoZXIgY2FuIGxlYWQgdG8NCmJldHRlciByZXN1bHRzLCBhbmQgdmljZSB2ZXJzYS4NCg0KVGhlIHN0ZXBzIHRvIGZvbGxvdyBhcmU6DQoNCjEuICBDcmVhdGUgYSBtYXRyaXggd2l0aCB0aGUgd2VpZ2h0cyBjb21iaW5hdGlvbnMNCjIuICBDYWxjdWxhdGUgdGhlIG5ldyBzaW11bGF0ZWQgaW52ZXN0bWVudHMNCjMuICBHZW5lcmF0ZSB0aGUgZm9yZWNhc3Qgd2l0aCB0aGUgbmV3IHNpbXVsYXRlZCB2YWx1ZXMNCg0KIyMjIFNpbXVsYXRpb24gd2VpZ2h0cyB7I3NpbXVsYXRpb24td2VpZ2h0c30NCg0KV2UgY3JlYXRlIGEgbWVzaCBvZiB2YWx1ZXMgdGhhdCBhbGxvdyB1cyB0byBldmFsdWF0ZSBkaWZmZXJlbnQgc2NlbmFyaW9zLiBUaGUgZm9sbG93aW5nDQpyZXN0cmljdGlvbnMgaGF2ZSBiZWVuIGFwcGxpZWQ6DQoNCi0gICBUaGUgd2VpZ2h0cyBtdXN0IGFkZCB1cCB0byAxDQoNCi0gICBJbiBvcmRlciB0byBkaXZlcnNpZnksIHRoZSBtYXhpbXVtIGFsbG9jYXRpb24gd2lsbCBiZSA4MCUgb2YgdGhlIGNhcGl0YWwuDQoNCmBgYHtyIHJhbmRvbS13ZWlnaHRzfQ0KIyAjIGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzQzMTU2NTUwL2dlbmVyYXRlLWEtcmFuZG9tLW1hdHJpeC1pbi1yLXdoaWNoLXRoZS1zdW0tb2YtZWFjaC1yb3dzLWlzLWVxdWFsLXRvLTENCg0KIyBDcmVhdGUgcmFuZG9tIHdlaWdodHMNCiMgcmFuZF93ZWlnaHRzIDwtIGZ1bmN0aW9uKG4pIHsNCiMgICB4IDwtIHNvcnQocnVuaWYobiAtIDEpKQ0KIyAgIGMoeCwgMSkgLSBjKDAsIHgpDQojIH0NCiMgd2VlaWdodHNfZGYgPC0gDQojICAgYXNfdGliYmxlKHQocmVwbGljYXRlKDQsIHJhbmRfd2VpZ2h0cygzKSkpKSAlPiUgDQojICAgc2V0X25hbWVzKGMoImludmVzdG1lbnRfMSIsICJpbnZlc3RtZW50XzIiLCAiaW52ZXN0bWVudF9vdGhlcnMiKSkNCiMgd2VlaWdodHNfZGYNCmBgYA0KDQpgYGB7ciBjcm9zc2luZy13ZWlnaHRzfQ0Kd2VpZ2h0c19kZiA8LSBjcm9zc2luZygNCiAgaW52ZXN0bWVudF8xID0gc2VxKDAsIDAuOCwgYnkgPSAwLjA1KSwgDQogIGludmVzdG1lbnRfMiA9IHNlcSgwLCAwLjgsIGJ5ID0gMC4wNSksDQogIGludmVzdG1lbnRfb3RoZXJzID0gc2VxKDAsIDAuOCwgYnkgPSAwLjA1KQ0KICApICU+JSANCiAgZmlsdGVyKGludmVzdG1lbnRfMSArIGludmVzdG1lbnRfMiArIGludmVzdG1lbnRfb3RoZXJzID09IDEpICU+JSANCiAgbXV0YXRlKA0KICAgIGNvbWJfaWQgPSByb3dfbnVtYmVyKCksIC5iZWZvcmUgPSAxTCwgDQogICAgY29tYl9kZXNjID0gc3ByaW50ZigiWyUuMmYsICUuMmYsICUuMmZdIiwgDQogICAgICAgICAgICAgICAgICAgICAgICBpbnZlc3RtZW50XzEsIGludmVzdG1lbnRfMiwgaW52ZXN0bWVudF9vdGhlcnMpDQogICkNCmBgYA0KDQpgYGB7ciBwcmludC1tZXNoLW9mLXdlaWdodHN9DQpoZWFkKHdlaWdodHNfZGYpICU+JSANCiAgdG9faHRtbChkaWdpdHMgPSAyLCBmdWxsX3dpZHRoID0gRkFMU0UpDQpgYGANCg0KQSB0b3RhbCBvZiBgciBtYXgod2VpZ2h0c19kZiRjb21iX2lkLCBuYS5ybSA9IFRSVUUpYCBjb21iaW5hdGlvbnMgcGVyIHNlcmllcyB3aWxsIGJlDQpldmFsdWF0ZWQuDQoNCiMjIyBDcmVhdGUgc2NlbmFyaW9zDQoNClRvIGdlbmVyYXRlIHRoZSBtdWx0aXBsZSBzY2VuYXJpb3Mgd2UgbXVzdCBtdWx0aXBseSB0aGUgd2VpZ2h0cyBnZW5lcmF0ZWQgaW4gdGhlIFtwcmV2aW91cw0Kc2VjdGlvbl0oI3NpbXVsYXRpb24td2VpZ2h0cykgd2l0aCB0aGUgdmFsdWVzIG9mIHRoZSBpbnZlc3RtZW50cy4gVG8gZG8gdGhpcywgd2Ugd2lsbCBoZWxwDQpvdXJzZWx2ZXMgd2l0aCB0aGUgZm9sbG93aW5nIGZ1bmN0aW9uOg0KDQpgYGB7ciBnZXQtZnV0dXJlLXNjZW5lcmFyaW9zLWZ1bmN0aW9uLCBlY2hvPVRSVUV9DQpnZXRfZnV0dXJlX3NjZW5lcmFyaW9zIDwtIGZ1bmN0aW9uKGZ1dHVyZV9kYXRhLCB3ZWlnaHRzX2RmKSB7DQogIA0KICAjIFN0b3JlIGlkIGRhdGENCiAgaWRfZGYgPC0gZnV0dXJlX2RhdGEgJT4lIA0KICAgIHNlbGVjdChpZCwgZGF0ZSkNCiAgDQogICMgQ2FsY3VsYXRlIHRvdGFsIGludmVzdGVkIGluIGVhY2ggcHJvZHVjdC1tb250aA0KICB0b3RhbF9pbnZlc3RlZCA8LSBmdXR1cmVfZGF0YSAlPiUgDQogICAgdHJhbnNtdXRlKHRvdGFsID0gcm93U3VtcyhhY3Jvc3MoY29udGFpbnMoImludmVzdG1lbnQiKSkpKQ0KICANCiAgIyBSZXBlYXQgYHRvdGFsX2ludmVzdGVkYCBjb2x1bW4gMyB0aW1lcyAob25lIGZvciBlYWNoIGludmVzdG1lbnQpDQogIGludiA8LSByZXBsaWNhdGUobiA9IDMsIHRvdGFsX2ludmVzdGVkJHRvdGFsKSANCiAgDQogICMgTG9vcCB0aHJvdWdoIHdlaWdodHMNCiAgaW52X2NvbHMgPC0gc3RyX3N1YnNldChuYW1lcyh3ZWlnaHRzX2RmKSwgImludmVzdG1lbnQiKQ0KICBzY2VuYXJpb3NfbGlzdCA8LSB2ZWN0b3IoImxpc3QiLCBsZW5ndGggPSBucm93KHdlaWdodHNfZGYpKQ0KICBmb3IgKGkgaW4gc2VxKDEsIG5yb3cod2VpZ2h0c19kZikpKSB7DQogICAgDQogICAgIyBXZWlnaHRzIGZvciB0aGlzIGl0ZXJhdGlvbg0KICAgIHcgPC0gd2VpZ2h0c19kZltpLCBpbnZfY29sc10NCiAgICB3IDwtIGFzLm51bWVyaWModykNCiAgICANCiAgICAjIE5ldyBpbnZlc3RtZW50cw0KICAgIG5ld19pbnZlc3RtZW50cyA8LSB0KHcgKiB0KGludikpDQogICAgY29sbmFtZXMobmV3X2ludmVzdG1lbnRzKSA8LSBpbnZfY29scw0KDQogICAgZnV0dXJlX3NjZW5hcmlvIDwtIGlkX2RmICU+JSANCiAgICAgIGJpbmRfY29scyh3ZWlnaHRzX2RmW2ksICJjb21iX2lkIl0pICU+JSANCiAgICAgIGJpbmRfY29scyhhc190aWJibGUobmV3X2ludmVzdG1lbnRzKSkNCiAgICANCiAgICBzY2VuYXJpb3NfbGlzdFtbaV1dIDwtIGZ1dHVyZV9zY2VuYXJpbw0KICB9DQogIA0KICAjIFJldHVybiBhIGxpc3Qgd2l0aCBhbGwgdGhlIHNpbXVsYXRpb25zDQogIHNjZW5hcmlvc19saXN0DQp9DQpgYGANCg0KYGBge3IgZ2VuZXJhdGUtc2NlbmFyaW9zfQ0KIyBOZXcgcHJlZGljdG9ycyB0byBiZSBmZWQgaW50byB0aGUgbW9kZWwNCmZ1dHVyZV9zY2VuYXJpb3MgPC0gZ2V0X2Z1dHVyZV9zY2VuZXJhcmlvcyh0ZXN0X2RhdGFfYWxsb2MsIHdlaWdodHNfZGYpDQoNCiMgRm9yZWNhc3RzIHdpdGggdGhlIHNpbXVsYXRlZCBkYXRhDQpmYyA8LSBmaXRfYWxsb2MgJT4lIA0KICBmb3JlY2FzdChuZXdfZGF0YSA9IGZ1dHVyZV9zY2VuYXJpb3MpDQpgYGANCg0KSW4gZ3JheS1ibHVlIGNvbG9yIHdlIHNlZSB0aGUgcG9zc2libGUgc2NlbmFyaW9zIG9mIHRoZSBmb3JlY2FzdC4gRWFjaCBzY2VuYXJpbw0KY29ycmVzcG9uZHMgdG8gYSBkaWZmZXJlbnQgd2VpZ2h0IGNvbWJpbmF0aW9uLiBJbiBvcmFuZ2Ugd2UgaGF2ZSB0aGUgbWVkaWFuIGFuZCBpbiBhbm90aGVyDQpzaGFkZSBvZiBibHVlIHRoZSA4MHRoIHF1YW50aWxlLg0KDQpgYGB7ciB2aXotc2ltdWxhdGlvbnN9DQp0aGlzX2lkIDwtICJDbHVzdGVyIDFfX0JyYW5kIEdyb3VwIDMxIg0KDQpmY19hZ2cgPC0gZmMgJT4lIA0KICBmaWx0ZXIoaWQgPT0gdGhpc19pZCkgJT4lIA0KICBhc190aWJibGUoKSAlPiUgDQogIGdyb3VwX2J5KGlkLCAubW9kZWwsIGRhdGUpICU+JSANCiAgc3VtbWFyaXNlKA0KICAgIG1lZGlhbiA9IG1lZGlhbigubWVhbiksIA0KICAgIHVwcGVyID0gcXVhbnRpbGUoLm1lYW4sIHByb2JzID0gMC44MCksDQogICAgbG93ZXIgPSBxdWFudGlsZSgubWVhbiwgcHJvYnMgPSAwLjIwKSwgDQogICAgLmdyb3VwcyA9ICJkcm9wIg0KICApDQoNCnRyYWluX2RhdGFfYWxsb2MgJT4lIA0KICBmaWx0ZXIoaWQgPT0gdGhpc19pZCkgJT4lDQogIGF1dG9wbG90KHNhbGVzXzIpICsNCiAgYXV0b2xheWVyKA0KICAgIGZjICU+JSBmaWx0ZXIoaWQgPT0gdGhpc19pZCksDQogICAgbGV2ZWwgPSBOVUxMLCBhbHBoYSA9IDAuMDUNCiAgKSArDQogIGdlb21fbGluZSgNCiAgICBkYXRhID0gZmNfYWdnLCBtYXBwaW5nID0gYWVzKHkgPSBtZWRpYW4pLA0KICAgIGNvbG91ciA9ICJvcmFuZ2UiLCBzaXplID0gMSwgYWxwaGEgPSAwLjcNCiAgKSArDQogIHNjYWxlX3lfY29udGludW91cygNCiAgICBsYWJlbHMgPSBzY2FsZXM6OmxhYmVsX251bWJlcihzdWZmaXggPSAiSyIsIHNjYWxlID0gMWUtMykNCiAgKSArDQogIGdlb21fbGluZSgNCiAgICBkYXRhID0gZmNfYWdnLCBtYXBwaW5nID0gYWVzKHkgPSB1cHBlciksDQogICAgY29sb3VyID0gInN0ZWVsYmx1ZSIsIHNpemUgPSAxLCBhbHBoYSA9IDAuNQ0KICApICsNCiAgIyBnZW9tX2xpbmUoDQogICMgICBkYXRhID0gZmNfYWdnLCBtYXBwaW5nID0gYWVzKHkgPSBsb3dlciksIA0KICAjICAgY29sb3VyID0gIm9yYW5nZSIsIHNpemUgPSAxLCBhbHBoYSA9IDAuNQ0KICAjICkgKw0KICBmYWNldF93cmFwKH4gaWQpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArDQogIGxhYnMoeCA9IE5VTEwsIHkgPSBOVUxMKQ0KYGBgDQoNCiMjIyBGaW5kIG9wdGltYWwgdmFsdWVzDQoNCldlIHdpbGwgdXNlIHRoZSA4MHRoIHF1YW50aWxlIGFzIHRoZSBiZXN0IGNvbWJpbmF0aW9uLiBXZSBjb3VsZCB1c2UgdGhlIGNvbWJpbmF0aW9uIG9mDQpwYXJhbWV0ZXJzIHRoYXQgaGFzIGdlbmVyYXRlZCB0aGUgZ3JlYXRlc3QgYmVuZWZpdHMsIGJ1dCBpdCB3b3VsZCBiZSBzZWxlY3QgdGhlIGJlc3QNCm9wdGltaXN0aWMgc2NlbmFyaW8gYW5kIHdlIHByZWZlciB0byBiZSBtb3JlIGNvbnNlcnZhdGl2ZS4NCg0KRmlyc3QsIHdlIGNhbGN1bGF0ZSB0aGUgdG90YWwgYW1vdW50IG9mIGVhY2ggc2ltdWxhdGlvbg0KDQpgYGB7ciBmaW5kLW9wdGltemFsLXZhbHVlcywgZWNobz1UUlVFfQ0Kc2ltdWxhdGlvbnNfYWdnIDwtIGZjICU+JSANCiAgYXNfdGliYmxlKCkgJT4lIA0KICBncm91cF9ieShpZCwgY29tYl9pZCkgJT4lIA0KICBzdW1tYXJpc2UoYWNyb3NzKGNvbnRhaW5zKCIubWVhbiIpIHwgY29udGFpbnMoImludmVzdG1lbnQiKSwgc3VtKSkgJT4lDQogIHVuZ3JvdXAoKSAlPiUgDQogIHJlbmFtZShPcHRpbWFsU2FsZXMgPSAubWVhbikgJT4lIA0KICBhcnJhbmdlKGRlc2MoT3B0aW1hbFNhbGVzKSkgJT4lIA0KICBsZWZ0X2pvaW4oc2VsZWN0KHdlaWdodHNfZGYsIGNvbWJfaWQsIGNvbWJfZGVzYyksIGJ5ID0gImNvbWJfaWQiKQ0KYGBgDQoNClRoZW4sIHNlbGVjdCB0aGUgY29tYmluYXRpb24gdGhhdCBtZWV0cyBvdXIgcmVxdWlyZW1lbnRzOiBgcGN0X3JhbmsgPD0gMC44YA0KDQpgYGB7ciBvcHRpbWFsLXZhbHVlcy1ieS1pZCwgZWNobz1UUlVFfQ0KIyBGaW5kIGJlc3QgY29tYmluYXRpb24gb2Ygd2VpZ2h0cyBmb3IgZWFjaCBgaWRgDQpvcHRpbWFsX3NpbXVsYXRpb25faWQgPC0gc2ltdWxhdGlvbnNfYWdnICU+JSANCiAgZ3JvdXBfYnkoaWQpICU+JQ0KICBzdW1tYXJpc2UoDQogICAgY29tYl9pZCA9IGNvbWJfaWQsDQogICAgT3B0aW1hbFNhbGVzID0gT3B0aW1hbFNhbGVzLA0KICAgIHBjdF9yYW5rID0gcGVyY2VudF9yYW5rKE9wdGltYWxTYWxlcykNCiAgKSAlPiUgDQogICMgU2VsZWN0IDgwIHBlcmNlbnRpbGUNCiAgZmlsdGVyKHBjdF9yYW5rIDw9IDAuOCkgJT4lIA0KICBzbGljZV9tYXgocGN0X3JhbmspICU+JQ0KICAjIEluIGNhc2Ugb2YgdGllLCBjaG9vc2UgdGhlIGZpcnN0IG9uZS4gVGhpcyBoYXBwZW5zDQogICMgaW4gYENsdXN0ZXIgNV9fQnJhbmQgR3JvdXAgMzBgDQogIHNsaWNlX2hlYWQobiA9IDEpICU+JSANCiAgdW5ncm91cCgpDQpgYGANCg0KYGBge3Igb3B0aW1hbC12YWx1ZXMtZGF0YWZyYW1lfQ0KIyBGb3IgZWFjaCBgaWRgIHNlbGVjdCB0aGUgYmVzdCBgY29tYl9pZGAgb2YgdGhlIGFnZ3JlZ2F0ZWQgdmFsdWVzIA0Kb3B0aW1hbF9zaW11bGF0aW9uX2RmIDwtIHNpbXVsYXRpb25zX2FnZyAlPiUgDQogIHNlbWlfam9pbihvcHRpbWFsX3NpbXVsYXRpb25faWQsIGJ5ID0gYygiaWQiLCAiY29tYl9pZCIpKQ0KYGBgDQoNCkZpbmFsbHksIHByZXBhcmUgdGhlIG91dHB1dCBkYXRhDQoNCmBgYHtyIHByZXBhcmUtc3VibWlzc2lvbi1kYXRhfQ0Kc3VibWlzc2lvbl90YmwgPC0gb3B0aW1hbF9zaW11bGF0aW9uX2RmICU+JSANCiAgcGl2b3RfbG9uZ2VyKA0KICAgIGNvbHMgPSAtYyhpZCwgY29tYl9pZCwgY29tYl9kZXNjLCBPcHRpbWFsU2FsZXMpLCANCiAgICBuYW1lc190byA9ICJmdW5jdGlvbiIsIA0KICAgIHZhbHVlc190byA9ICJPcHRpbWlzZUludmVzdG1lbnQiDQogICkgJT4lIA0KICBsZWZ0X2pvaW4oZmNfYWdnXzIwMTgsIGJ5ID0gImlkIikgJT4lIA0KICBzZWxlY3QoaWQsIGBmdW5jdGlvbmAsIE9wdGltaXNlSW52ZXN0bWVudCwgRm9yZWNhc3RlZFNhbGVzLCBPcHRpbWFsU2FsZXMpDQoNCg0KaGVhZChzdWJtaXNzaW9uX3RibCkgJT4lIA0KICB0b19odG1sKGRpZ2l0cyA9IDApDQpgYGANCg0KQWNjb3JkaW5nIHRvIHRoZSBzaW11bGF0aW9uIHJlc3VsdHMsIHdlIGNvdWxkIGhhdmUgaGFkIGEgcHJvZml0IG9mIFx+IDUwMGsgaW4gMjAxOC4NCg0KYGBge3J9DQpzdWJtaXNzaW9uX3RibCAlPiUgDQogIGZpbHRlcihgZnVuY3Rpb25gID09ICJpbnZlc3RtZW50XzEiKSAlPiUgDQogIHN1bW1hcmlzZShhY3Jvc3MoaXMubnVtZXJpYywgc3VtKSkgJT4lIA0KICBtdXRhdGUoUHJvZml0ID0gT3B0aW1hbFNhbGVzIC0gRm9yZWNhc3RlZFNhbGVzKSAlPiUgDQogIGFkZF9jb2x1bW4oWWVhciA9ICIyMDE4IiwgLmJlZm9yZSA9IDFMKSAlPiUgDQogIHRvX2h0bWwoZGlnaXRzID0gMCwgZnVsbF93aWR0aCA9IEZBTFNFKQ0KYGBgDQoNCiMjIEV2b2x1dGlvbiBvZiBpbnZlc3RtZW50cw0KDQpUaGUgZXZvbHV0aW9uIG9mIHRoZSBpbnZlc3RtZW50cyBvdmVyIHRoZSB5ZWFycyBpcyBzaG93biBiZWxvdy5JdCBjYW4gYmUgc2VlbiBob3csIGluDQpnZW5lcmFsIHRlcm1zLCB0aGUgaW52ZXN0bWVudHMgZm9yIDIwMTggYXJlIGFsaWduZWQgd2l0aCB0aGUgaGlzdG9yaWNhbCB0cmVuZHMgYW5kIGRvIG5vdA0KZGlmZmVyZW50IHNoYXJwbHkgZnJvbSB0aGUgcmVjZW50IHBhc3QuIEhvd2V2ZXIsIHRoZXJlIGFyZSBzb21lIGludmVzdG1lbnRzIHRoYXQgaGF2ZSBiZWVuDQphZmZlY3RlZCBtb3JlIHRoYW4gdGhlIHJlc3QuDQoNCmBgYHtyIHdlaWdodHMtYW5hbHlzaXMtMDF9DQp3ZWlnaHRzXzIwMTggPC0gb3B0aW1hbF9zaW11bGF0aW9uX2RmICU+JSANCiAgc2VwYXJhdGUoaWQsIGludG8gPSBjKCJjbHVzdGVyIiwgImJyYW5kIiksIHNlcCA9ICJfXyIsIHJlbW92ZSA9IEZBTFNFKSAlPiUgDQogIGdyb3VwX2J5KGJyYW5kLCB5ZWFyID0gMjAxOCkgJT4lIA0KICBzdW1tYXJpc2UoYWNyb3NzKGNvbnRhaW5zKCJpbnZlc3RtZW50IiksIHN1bSkpDQoNCiMgV2VpZ2h0cyBieSB5ZWFyDQpwbG90X2RhdGEgPC0gdHJhaW5fZGF0YV9hbGxvYyAlPiUgDQogIGFzX3RpYmJsZSgpICU+JSANCiAgZ3JvdXBfYnkoYnJhbmQsIHllYXIgPSB5ZWFyKGRhdGUpKSAlPiUgDQogIHN1bW1hcmlzZShhY3Jvc3MoY29udGFpbnMoImludmVzdG1lbnQiKSwgc3VtKSkgJT4lIA0KICBmaWx0ZXIoeWVhciA+PSAyMDE0KSAlPiUgDQogIGJpbmRfcm93cyh3ZWlnaHRzXzIwMTgpDQpgYGANCg0KYGBge3Igdml6LWV2b2x1dGlvbi1pbnYtMSwgZmlnLmhlaWdodD01LCBmaWcud2lkdGg9OH0NCnBsb3RfZGF0YSAlPiUgDQogIHBpdm90X3dpZGVyKA0KICAgIGlkX2NvbHMgPSBicmFuZCwgDQogICAgbmFtZXNfZnJvbSA9IHllYXIsIA0KICAgIHZhbHVlc19mcm9tID0gaW52ZXN0bWVudF8xDQogICkgJT4lIA0KICBtdXRhdGUoaWRfbnVtID0gc3RyX3JlcGxhY2UoYnJhbmQsICJCcmFuZCBHcm91cCAiLCAiIikgJT4lIGFzLmludGVnZXIoKSkgJT4lIA0KICBwbG90X2x5KCkgJT4lIA0KICBhZGRfdHJhY2UoDQogICAgdHlwZSA9ICdwYXJjb29yZHMnLA0KICAgIGxpbmUgPSBsaXN0KA0KICAgICAgY29sb3IgPSB+aWRfbnVtLA0KICAgICAgY29sb3JzY2FsZSA9ICdKZXQnLA0KICAgICAgc2hvd3NjYWxlID0gVFJVRSwNCiAgICAgIHJldmVyc2VzY2FsZSA9IFRSVUUNCiAgICApLA0KICAgIGRpbWVuc2lvbnMgPSBsaXN0KA0KICAgICAgbGlzdChyYW5nZSA9IGMoLTI1ZTQsIDApLCBsYWJlbCA9ICIyMDE0IiwgdmFsdWVzID0gfiBgMjAxNGApLA0KICAgICAgbGlzdChyYW5nZSA9IGMoLTI1ZTQsIDApLCBsYWJlbCA9ICIyMDE1IiwgdmFsdWVzID0gfiBgMjAxNWApLA0KICAgICAgbGlzdChyYW5nZSA9IGMoLTI1ZTQsIDApLCBsYWJlbCA9ICIyMDE2IiwgdmFsdWVzID0gfiBgMjAxNmApLA0KICAgICAgbGlzdChyYW5nZSA9IGMoLTI1ZTQsIDApLCBsYWJlbCA9ICIyMDE3IiwgdmFsdWVzID0gfiBgMjAxN2ApLA0KICAgICAgbGlzdChyYW5nZSA9IGMoLTI1ZTQsIDApLCBsYWJlbCA9ICIyMDE4IiwgdmFsdWVzID0gfiBgMjAxOGApDQogICAgKQ0KICApICU+JSANCiAgbGF5b3V0KHRpdGxlID0gbGlzdCh0ZXh0ID0gIkV2b2x1dGlvbiBvZiBJbnZlc3RtZW50IDEiKSkNCmBgYA0KDQpgYGB7ciB2aXotZXZvbHV0aW9uLWludi0yLCBmaWcuaGVpZ2h0PTUsIGZpZy53aWR0aD04fQ0KcGxvdF9kYXRhICU+JSANCiAgcGl2b3Rfd2lkZXIoDQogICAgaWRfY29scyA9IGJyYW5kLCANCiAgICBuYW1lc19mcm9tID0geWVhciwgDQogICAgdmFsdWVzX2Zyb20gPSBpbnZlc3RtZW50XzINCiAgKSAlPiUgDQogIG11dGF0ZShpZF9udW0gPSBzdHJfcmVwbGFjZShicmFuZCwgIkJyYW5kIEdyb3VwICIsICIiKSAlPiUgYXMuaW50ZWdlcigpKSAlPiUgDQogIHBsb3RfbHkoKSAlPiUgDQogIGFkZF90cmFjZSgNCiAgICB0eXBlID0gJ3BhcmNvb3JkcycsDQogICAgbGluZSA9IGxpc3QoDQogICAgICBjb2xvciA9IH5pZF9udW0sDQogICAgICBjb2xvcnNjYWxlID0gJ0pldCcsDQogICAgICBzaG93c2NhbGUgPSBUUlVFLA0KICAgICAgcmV2ZXJzZXNjYWxlID0gVFJVRQ0KICAgICksDQogICAgZGltZW5zaW9ucyA9IGxpc3QoDQogICAgICBsaXN0KHJhbmdlID0gYygtMWU1LCAwKSwgbGFiZWwgPSAiMjAxNCIsIHZhbHVlcyA9IH4gYDIwMTRgKSwNCiAgICAgIGxpc3QocmFuZ2UgPSBjKC0xZTUsIDApLCBsYWJlbCA9ICIyMDE1IiwgdmFsdWVzID0gfiBgMjAxNWApLA0KICAgICAgbGlzdChyYW5nZSA9IGMoLTFlNSwgMCksIGxhYmVsID0gIjIwMTYiLCB2YWx1ZXMgPSB+IGAyMDE2YCksDQogICAgICBsaXN0KHJhbmdlID0gYygtMWU1LCAwKSwgbGFiZWwgPSAiMjAxNyIsIHZhbHVlcyA9IH4gYDIwMTdgKSwNCiAgICAgIGxpc3QocmFuZ2UgPSBjKC0xZTUsIDApLCBsYWJlbCA9ICIyMDE4IiwgdmFsdWVzID0gfiBgMjAxOGApDQogICAgKQ0KICApICU+JSANCiAgbGF5b3V0KHRpdGxlID0gIkV2b2x1dGlvbiBvZiBJbnZlc3RtZW50IDIiKQ0KYGBgDQoNCkluIGdlbmVyYWwsIGl0IGlzIHN1Z2dlc3RlZCB0byBpbnZlc3QgbW9yZSBpbiAqb3RoZXJzKiBmb3IgdGhlIDIwMTguDQoNCmBgYHtyIHZpei1ldm9sdXRpb24taW52LW90aGVycywgZmlnLmhlaWdodD01LCBmaWcud2lkdGg9OH0NCnBsb3RfZGF0YSAlPiUgDQogIHBpdm90X3dpZGVyKA0KICAgIGlkX2NvbHMgPSBicmFuZCwgDQogICAgbmFtZXNfZnJvbSA9IHllYXIsIA0KICAgIHZhbHVlc19mcm9tID0gaW52ZXN0bWVudF9vdGhlcnMNCiAgKSAlPiUgDQogIG11dGF0ZShpZF9udW0gPSBzdHJfcmVwbGFjZShicmFuZCwgIkJyYW5kIEdyb3VwICIsICIiKSAlPiUgYXMuaW50ZWdlcigpKSAlPiUgDQogIHBsb3RfbHkoKSAlPiUgDQogIGFkZF90cmFjZSgNCiAgICB0eXBlID0gJ3BhcmNvb3JkcycsDQogICAgbGluZSA9IGxpc3QoDQogICAgICBjb2xvciA9IH5pZF9udW0sDQogICAgICBjb2xvcnNjYWxlID0gJ0pldCcsDQogICAgICBzaG93c2NhbGUgPSBUUlVFLA0KICAgICAgcmV2ZXJzZXNjYWxlID0gVFJVRQ0KICAgICksDQogICAgZGltZW5zaW9ucyA9IGxpc3QoDQogICAgICBsaXN0KHJhbmdlID0gYygtNy4xZTQsIDApLCBsYWJlbCA9ICIyMDE0IiwgdmFsdWVzID0gfiBgMjAxNGApLA0KICAgICAgbGlzdChyYW5nZSA9IGMoLTcuMWU0LCAwKSwgbGFiZWwgPSAiMjAxNSIsIHZhbHVlcyA9IH4gYDIwMTVgKSwNCiAgICAgIGxpc3QocmFuZ2UgPSBjKC03LjFlNCwgMCksIGxhYmVsID0gIjIwMTYiLCB2YWx1ZXMgPSB+IGAyMDE2YCksDQogICAgICBsaXN0KHJhbmdlID0gYygtNy4xZTQsIDApLCBsYWJlbCA9ICIyMDE3IiwgdmFsdWVzID0gfiBgMjAxN2ApLA0KICAgICAgbGlzdChyYW5nZSA9IGMoLTcuMWU0LCAwKSwgbGFiZWwgPSAiMjAxOCIsIHZhbHVlcyA9IH4gYDIwMThgKQ0KICAgICkNCiAgKSAlPiUgDQogIGxheW91dCh0aXRsZSA9ICJFdm9sdXRpb24gb2YgSW52ZXN0bWVudCBPdGhlcnMiKQ0KYGBgDQoNCiMgV2hhdCdzIG5leHQNCg0KSSB3aWxsIGxlYXZlIHNvbWUgaWRlYXMgdGhhdCBiZSBleHBsb3JlZCB0byBleHBhbmQgdGhlIGFuYWx5c2lzDQoNCi0gICBSZW1vdmUgb3V0bGllcnMgYW5kIGNsZWFuIHRoZSBkYXRhLg0KLSAgIFRpbWUgc2VyaWVzIGNsdXN0ZXJpbmcgYmFzZWQgb24gZmVhdHVyZXMgc3VjaCBhcyB0cmVuZCBzdHJlbmd0aCwgc2Vhc29uYWxpdHksDQogICAgc3Bpa2luZXNzLCBsaW5lYXJpdHksIGF1dG9jb3JyZWxhdGlvbiwgZXRjLg0KLSAgIFRlc3QgaWYgZW5zZW1ibGVzIGRvIGltcHJvdmUgdGhlIGFjY3VyYWN5LiBUaGVyZSBhcmUgbWFueSB0eXBlcyBvZiBlbnNlbWJsZXMgdG8NCiAgICBleHBsb3JlOiBjb21iaW5hdGlvbiBlbnNlbWJsZXMsIHdlaWdodGVkIGF2ZXJhZ2UgZW5zZW1ibGVzIGJhc2VkIG9uIGNyb3NzIHZhbGlkYXRpb24NCiAgICBlcnJvcnMgb3IgZXZlbiBtb3JlIGFkdmFuY2VkIHVzaW5nIHJlZ3VsYXJpemVkIGxpbmVhciBtb2RlbHMgdG8gbmFtZSBhIGZldy4NCi0gICBVc2UgbW9yZSB0aGFuIG9uZSBmb2xkIHRvIHNlbGVjdCB0aGUgYmVzdCBtb2RlbHMsIGkuZSB1c2UgdGltZSBzZXJpZXMgY3Jvc3MNCiAgICB2YWxpZGF0aW9uLg0KLSAgIERpcmVjdGx5IGZpbmQgdGhlIGJlc3QgbW9kZWwgaW4gdGhlIGZpcnN0IGNoYWxsZW5nZSBzbyBpdCBjYW4gYmUgdXNlZCBpbiB0aGUNCiAgICBvcHRpbWl6YXRpb24gcHJvYmxlbS4NCi0gICBUcnkgb3RoZXJzIG1ldGhvZHMgc3VjaCBhcyBwcm9waGV0LCBtYWNoaW5lIGxlYXJuaW5nIG9yIG90aGVycy4NCi0gICBBY2NvdW50IGZvciB1bmNlcnRhaW50eSBtZWFzdXJlcywgYmVjYXVzZSBhbGwgaXMgbm90IGFib3V0IGFjY3VyYWN5LCBwcmVkaWN0aW9uDQogICAgaW50ZXJ2YWxzIGFyZSBhbHNvIGltcG9ydGFudC4NCi0gICBUcnkgb3RoZXIgb3B0aW1pemF0aW9uIG1ldGhvZHMNCg==